Merge "Fix a potential NPE" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 3091354..09abe2b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9854,7 +9854,7 @@
     method @NonNull public android.content.AttributionSource build();
     method @NonNull public android.content.AttributionSource.Builder setAttributionTag(@Nullable String);
     method @FlaggedApi("android.permission.flags.device_aware_permission_apis") @NonNull public android.content.AttributionSource.Builder setDeviceId(int);
-    method @Deprecated @NonNull public android.content.AttributionSource.Builder setNext(@Nullable android.content.AttributionSource);
+    method @NonNull public android.content.AttributionSource.Builder setNext(@Nullable android.content.AttributionSource);
     method @FlaggedApi("android.permission.flags.set_next_attribution_source") @NonNull public android.content.AttributionSource.Builder setNextAttributionSource(@NonNull android.content.AttributionSource);
     method @NonNull public android.content.AttributionSource.Builder setPackageName(@Nullable String);
     method @NonNull public android.content.AttributionSource.Builder setPid(int);
@@ -32840,7 +32840,7 @@
     method public static android.os.Message obtain(android.os.Handler, int, Object);
     method public static android.os.Message obtain(android.os.Handler, int, int, int);
     method public static android.os.Message obtain(android.os.Handler, int, int, int, Object);
-    method public android.os.Bundle peekData();
+    method @Nullable public android.os.Bundle peekData();
     method public void recycle();
     method public void sendToTarget();
     method public void setAsynchronous(boolean);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4f8e8dd..014ddd41 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3484,9 +3484,20 @@
         // only do this if the user already has more than one preferred locale
         if (android.content.res.Flags.defaultLocale()
                 && r.getConfiguration().getLocales().size() > 1) {
-            LocaleConfig lc = getUserId() < 0
-                    ? LocaleConfig.fromContextIgnoringOverride(this)
-                    : new LocaleConfig(this);
+            LocaleConfig lc;
+            if (getUserId() < 0) {
+                lc = LocaleConfig.fromContextIgnoringOverride(this);
+            } else {
+                // This is needed because the app might have locale config overrides that need to
+                // be read from disk in order for resources to correctly choose which values to
+                // load.
+                StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
+                try {
+                    lc = new LocaleConfig(this);
+                } finally {
+                    StrictMode.setThreadPolicy(policy);
+                }
+            }
             mResourcesManager.setLocaleConfig(lc);
         }
     }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 6009c29..24a5157 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -159,7 +159,8 @@
      * Loads {@link ApkAssets} and caches them to prevent their garbage collection while the
      * instance is alive and reachable.
      */
-    private class ApkAssetsSupplier {
+    @VisibleForTesting
+    protected class ApkAssetsSupplier {
         final ArrayMap<ApkKey, ApkAssets> mLocalCache = new ArrayMap<>();
 
         /**
@@ -544,7 +545,10 @@
      * from an {@link ApkAssetsSupplier} if non-null; otherwise ApkAssets are loaded using
      * {@link #loadApkAssets(ApkKey)}.
      */
-    private @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key,
+
+    @VisibleForTesting
+    @UnsupportedAppUsage
+    protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key,
             @Nullable ApkAssetsSupplier apkSupplier) {
         final AssetManager.Builder builder = new AssetManager.Builder();
 
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 6a03c17..ce1d43d 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -180,6 +180,11 @@
 
     @Override
     public void injectInputEventToInputFilter(InputEvent event) throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
         mAccessibilityManager.injectInputEventToInputFilter(event);
     }
 
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 4b2cee6..697c25c 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -730,10 +730,7 @@
 
         /**
          * The next app to receive the permission protected data.
-         *
-         * @deprecated Use {@link #setNextAttributionSource} instead.
          */
-        @Deprecated
         public @NonNull Builder setNext(@Nullable AttributionSource value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x20;
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
index d4ce0eb..5cbb0bb 100644
--- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -16,8 +16,6 @@
 
 package android.hardware.camera2.params;
 
-import static com.android.internal.R.string.hardware;
-
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index da647e2..161951e 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -437,6 +438,7 @@
      * @see #getData()
      * @see #setData(Bundle)
      */
+    @Nullable
     public Bundle peekData() {
         return data;
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7a6c292..cac5387 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -991,7 +991,7 @@
     // for idleness handling.
     private boolean mHasIdledMessage = false;
     // time for touch boost period.
-    private static final int FRAME_RATE_TOUCH_BOOST_TIME = 1500;
+    private static final int FRAME_RATE_TOUCH_BOOST_TIME = 3000;
     // time for checking idle status periodically.
     private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500;
     // time for revaluating the idle status before lowering the frame rate.
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index e177731..c6bd20c 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -79,4 +79,9 @@
      * Used by Settings to enable/disable multiprocess.
      */
     void enableMultiProcess(boolean enable);
+
+    /**
+     * Used by Settings to get the default WebView package.
+     */
+    WebViewProviderInfo getDefaultWebViewPackage();
 }
diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
index f5fe12e..e55c641 100644
--- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
+++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
@@ -37,22 +37,11 @@
      * @return The highest refresh rate
      */
     public static float findHighestRefreshRateForDefaultDisplay(Context context) {
-        return findHighestRefreshRate(context, Display.DEFAULT_DISPLAY);
-    }
-
-    /**
-     * Find the highest refresh rate among all the modes of the specified display.
-     *
-     * @param context The context
-     * @param displayId The display ID
-     * @return The highest refresh rate
-     */
-    public static float findHighestRefreshRate(Context context, int displayId) {
         final DisplayManager dm = context.getSystemService(DisplayManager.class);
-        final Display display = dm.getDisplay(displayId);
+        final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
 
         if (display == null) {
-            Log.w(TAG, "No valid display device with ID = " + displayId);
+            Log.w(TAG, "No valid default display device");
             return DEFAULT_REFRESH_RATE;
         }
 
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index 87c167c..4a9cb71 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -83,6 +83,12 @@
             }
 
             @Override
+            protected AssetManager createAssetManager(@NonNull final ResourcesKey key,
+                    ResourcesManager.ApkAssetsSupplier apkSupplier) {
+                return createAssetManager(key);
+            }
+
+            @Override
             protected DisplayMetrics getDisplayMetrics(int displayId, DisplayAdjustments daj) {
                 return mDisplayMetricsMap.get(displayId);
             }
@@ -100,7 +106,7 @@
                 null, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(newResources);
-        assertSame(resources, newResources);
+        assertSame(resources.getImpl(), newResources.getImpl());
     }
 
     @SmallTest
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 5e16bce..dd703f5 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -33,7 +33,6 @@
 import android.util.Log;
 
 import java.util.Calendar;
-import java.util.Objects;
 
 /**
  * @hide This should not be made public in its present form because it
@@ -139,13 +138,25 @@
         return new KeyStore2();
     }
 
+    /**
+     * Gets the {@link IKeystoreService} that should be started in early_hal in Android.
+     *
+     * @throws IllegalStateException if the KeystoreService is not available or has not
+     * been initialized when called. This is a state that should not happen and indicates
+     * and error somewhere in the stack or with the calling processes access permissions.
+     */
     @NonNull private synchronized IKeystoreService getService(boolean retryLookup) {
         if (mBinder == null || retryLookup) {
             mBinder = IKeystoreService.Stub.asInterface(ServiceManager
-                    .getService(KEYSTORE2_SERVICE_NAME));
-            Binder.allowBlocking(mBinder.asBinder());
+                .getService(KEYSTORE2_SERVICE_NAME));
         }
-        return Objects.requireNonNull(mBinder);
+        if (mBinder == null) {
+            throw new IllegalStateException(
+                    "Could not connect to Keystore service. Keystore may have crashed or not been"
+                            + " initialized");
+        }
+        Binder.allowBlocking(mBinder.asBinder());
+        return mBinder;
     }
 
     void delete(KeyDescriptor descriptor) throws KeyStoreException {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
index 6429b00..fafd37b 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml
@@ -45,12 +45,15 @@
         <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
         <option name="run-command" value="settings put system show_touches 1"/>
         <option name="run-command" value="settings put system pointer_location 1"/>
+        <option name="run-command" value="settings put global package_verifier_user_consent -1"/>
         <option name="teardown-command"
                 value="settings delete secure show_ime_with_hard_keyboard"/>
         <option name="teardown-command" value="settings delete system show_touches"/>
         <option name="teardown-command" value="settings delete system pointer_location"/>
         <option name="teardown-command"
                 value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/>
+        <option name="teardown-command"
+                value="settings put global package_verifier_user_consent 1"/>
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true"/>
@@ -76,6 +79,8 @@
                 value="appops set com.android.shell android:mock_location deny"/>
     </target_preparer>
 
+    <target_preparer class="com.android.csuite.core.AppCrawlTesterHostPreparer"/>
+
     <!-- Use app crawler to log into Netflix -->
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="run-command"
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index a1d6ab5..b1cf96d 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -113,13 +113,13 @@
   }
 
   public final class GnssMeasurementRequest implements android.os.Parcelable {
-    method @NonNull public android.os.WorkSource getWorkSource();
+    method @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE) @NonNull public android.os.WorkSource getWorkSource();
     method public boolean isCorrelationVectorOutputsEnabled();
   }
 
   public static final class GnssMeasurementRequest.Builder {
     method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
+    method @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE) @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
   }
 
   public final class GnssReflectingPlane implements android.os.Parcelable {
diff --git a/location/java/android/location/GnssMeasurementRequest.java b/location/java/android/location/GnssMeasurementRequest.java
index 65af392..2f0835a 100644
--- a/location/java/android/location/GnssMeasurementRequest.java
+++ b/location/java/android/location/GnssMeasurementRequest.java
@@ -17,11 +17,13 @@
 package android.location;
 
 import android.Manifest;
+import android.annotation.FlaggedApi;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.location.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.WorkSource;
@@ -121,6 +123,7 @@
      *
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE)
     @SystemApi
     public @NonNull WorkSource getWorkSource() {
         return mWorkSource;
@@ -298,6 +301,7 @@
          *
          * @hide
          */
+        @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE)
         @SystemApi
         @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
         public @NonNull Builder setWorkSource(@Nullable WorkSource workSource) {
diff --git a/location/java/android/location/flags/gnss.aconfig b/location/java/android/location/flags/gnss.aconfig
index c471a27..b6055e8 100644
--- a/location/java/android/location/flags/gnss.aconfig
+++ b/location/java/android/location/flags/gnss.aconfig
@@ -5,4 +5,18 @@
     namespace: "location"
     description: "Flag for GNSS API for NavIC L1"
     bug: "302199306"
-}
\ No newline at end of file
+}
+
+flag {
+    name: "gnss_call_stop_before_set_position_mode"
+    namespace: "location"
+    description: "Flag for calling stop() before setPositionMode()"
+    bug: "306874828"
+}
+
+flag {
+    name: "gnss_api_measurement_request_work_source"
+    namespace: "location"
+    description: "Flag for GnssMeasurementRequest WorkSource API"
+    bug: "295235160"
+}
diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp
index fe26dc3..991fe41 100644
--- a/packages/CredentialManager/Android.bp
+++ b/packages/CredentialManager/Android.bp
@@ -16,10 +16,12 @@
 
     dex_preopt: {
         profile_guided: true,
+        //TODO: b/312357299 - Update baseline profile
         profile: "profile.txt.prof",
     },
 
     static_libs: [
+        "CredentialManagerShared",
         "PlatformComposeCore",
         "androidx.activity_activity-compose",
         "androidx.appcompat_appcompat",
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
index 42f1207..325d3f8 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
@@ -16,6 +16,7 @@
 
 package com.android.credentialmanager
 
+import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.credentials.ui.RequestInfo
@@ -27,10 +28,10 @@
 import com.android.credentialmanager.model.Request
 
 fun Intent.parse(
-    packageManager: PackageManager,
+    context: Context,
 ): Request {
-    return parseCancelUiRequest(packageManager)
-        ?: parseRequestInfo()
+    return parseCancelUiRequest(context.packageManager)
+        ?: parseRequestInfo(context)
 }
 
 fun Intent.parseCancelUiRequest(packageManager: PackageManager): Request? =
@@ -51,11 +52,11 @@
         }
     }
 
-fun Intent.parseRequestInfo(): Request =
+fun Intent.parseRequestInfo(context: Context): Request =
     requestInfo.let{ info ->
         when (info?.type) {
             RequestInfo.TYPE_CREATE -> Request.Create(info.token)
-            RequestInfo.TYPE_GET -> toGet()
+            RequestInfo.TYPE_GET -> toGet(context)
             else -> {
                 throw IllegalStateException("Unrecognized request type: ${info?.type}")
             }
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
index 83183b5..3ef65b0 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
@@ -16,8 +16,8 @@
 
 package com.android.credentialmanager.client.impl
 
+import android.content.Context
 import android.content.Intent
-import android.content.pm.PackageManager
 import android.credentials.ui.BaseDialogResult
 import android.credentials.ui.UserSelectionDialogResult
 import android.os.Bundle
@@ -26,12 +26,13 @@
 import com.android.credentialmanager.model.Request
 import com.android.credentialmanager.parse
 import com.android.credentialmanager.client.CredentialManagerClient
+import dagger.hilt.android.qualifiers.ApplicationContext
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import javax.inject.Inject
 
 class CredentialManagerClientImpl @Inject constructor(
-        private val packageManager: PackageManager,
+    @ApplicationContext private val context: Context,
 ) : CredentialManagerClient {
 
     private val _requests = MutableStateFlow<Request?>(null)
@@ -40,7 +41,7 @@
 
     override fun updateRequest(intent: Intent) {
         val request = intent.parse(
-            packageManager = packageManager,
+            context = context,
         )
         Log.d(TAG, "Request parsed: $request, client instance: $this")
         if (request is Request.Cancel || request is Request.Close) {
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
new file mode 100644
index 0000000..f063074
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2023 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.credentialmanager.ktx
+
+import android.app.slice.Slice
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.credentials.Credential
+import android.credentials.flags.Flags
+import android.credentials.ui.AuthenticationEntry
+import android.credentials.ui.Entry
+import android.credentials.ui.GetCredentialProviderData
+import android.graphics.drawable.Drawable
+import android.text.TextUtils
+import android.util.Log
+import androidx.activity.result.IntentSenderRequest
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.provider.Action
+import androidx.credentials.provider.AuthenticationAction
+import androidx.credentials.provider.CredentialEntry
+import androidx.credentials.provider.CustomCredentialEntry
+import androidx.credentials.provider.PasswordCredentialEntry
+import androidx.credentials.provider.PublicKeyCredentialEntry
+import androidx.credentials.provider.RemoteEntry
+import com.android.credentialmanager.IS_AUTO_SELECTED_KEY
+import com.android.credentialmanager.model.get.ActionEntryInfo
+import com.android.credentialmanager.model.get.AuthenticationEntryInfo
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.get.ProviderInfo
+import com.android.credentialmanager.model.get.RemoteEntryInfo
+import com.android.credentialmanager.TAG
+
+fun CredentialEntryInfo.getIntentSenderRequest(
+    isAutoSelected: Boolean = false
+): IntentSenderRequest? {
+    val entryIntent = fillInIntent?.putExtra(IS_AUTO_SELECTED_KEY, isAutoSelected)
+
+    return pendingIntent?.let{
+        IntentSenderRequest
+            .Builder(pendingIntent = it)
+            .setFillInIntent(entryIntent)
+            .build()
+    }
+}
+
+// Returns the list (potentially empty) of enabled provider.
+fun List<GetCredentialProviderData>.toProviderList(
+    context: Context,
+): List<ProviderInfo> {
+    val providerList: MutableList<ProviderInfo> = mutableListOf()
+    this.forEach {
+        val providerLabelAndIcon = getServiceLabelAndIcon(
+            context.packageManager,
+            it.providerFlattenedComponentName
+        ) ?: return@forEach
+        val (providerLabel, providerIcon) = providerLabelAndIcon
+        providerList.add(
+            ProviderInfo(
+                id = it.providerFlattenedComponentName,
+                icon = providerIcon,
+                displayName = providerLabel,
+                credentialEntryList = getCredentialOptionInfoList(
+                    providerId = it.providerFlattenedComponentName,
+                    providerLabel = providerLabel,
+                    credentialEntries = it.credentialEntries,
+                    context = context
+                ),
+                authenticationEntryList = getAuthenticationEntryList(
+                    it.providerFlattenedComponentName,
+                    providerLabel,
+                    providerIcon,
+                    it.authenticationEntries),
+                remoteEntry = getRemoteEntry(
+                    it.providerFlattenedComponentName,
+                    it.remoteEntry
+                ),
+                actionEntryList = getActionEntryList(
+                    it.providerFlattenedComponentName, it.actionChips, providerIcon
+                ),
+            )
+        )
+    }
+    return providerList
+}
+
+/**
+ * Note: caller required handle empty list due to parsing error.
+ */
+private fun getCredentialOptionInfoList(
+    providerId: String,
+    providerLabel: String,
+    credentialEntries: List<Entry>,
+    context: Context,
+): List<CredentialEntryInfo> {
+    val result: MutableList<CredentialEntryInfo> = mutableListOf()
+    credentialEntries.forEach {
+        val credentialEntry = it.slice.credentialEntry
+        when (credentialEntry) {
+            is PasswordCredentialEntry -> {
+                result.add(
+                    CredentialEntryInfo(
+                    providerId = providerId,
+                    providerDisplayName = providerLabel,
+                    entryKey = it.key,
+                    entrySubkey = it.subkey,
+                    pendingIntent = credentialEntry.pendingIntent,
+                    fillInIntent = it.frameworkExtrasIntent,
+                    credentialType = CredentialType.PASSWORD,
+                    credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
+                    userName = credentialEntry.username.toString(),
+                    displayName = credentialEntry.displayName?.toString(),
+                    icon = credentialEntry.icon.loadDrawable(context),
+                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    lastUsedTimeMillis = credentialEntry.lastUsedTime,
+                    isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
+                            credentialEntry.autoSelectAllowedFromOption,
+                )
+                )
+            }
+            is PublicKeyCredentialEntry -> {
+                result.add(
+                    CredentialEntryInfo(
+                    providerId = providerId,
+                    providerDisplayName = providerLabel,
+                    entryKey = it.key,
+                    entrySubkey = it.subkey,
+                    pendingIntent = credentialEntry.pendingIntent,
+                    fillInIntent = it.frameworkExtrasIntent,
+                    credentialType = CredentialType.PASSKEY,
+                    credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
+                    userName = credentialEntry.username.toString(),
+                    displayName = credentialEntry.displayName?.toString(),
+                    icon = credentialEntry.icon.loadDrawable(context),
+                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    lastUsedTimeMillis = credentialEntry.lastUsedTime,
+                    isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
+                            credentialEntry.autoSelectAllowedFromOption,
+                )
+                )
+            }
+            is CustomCredentialEntry -> {
+                result.add(
+                    CredentialEntryInfo(
+                    providerId = providerId,
+                    providerDisplayName = providerLabel,
+                    entryKey = it.key,
+                    entrySubkey = it.subkey,
+                    pendingIntent = credentialEntry.pendingIntent,
+                    fillInIntent = it.frameworkExtrasIntent,
+                    credentialType = CredentialType.UNKNOWN,
+                    credentialTypeDisplayName =
+                    credentialEntry.typeDisplayName?.toString().orEmpty(),
+                    userName = credentialEntry.title.toString(),
+                    displayName = credentialEntry.subtitle?.toString(),
+                    icon = credentialEntry.icon.loadDrawable(context),
+                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    lastUsedTimeMillis = credentialEntry.lastUsedTime,
+                    isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
+                            credentialEntry.autoSelectAllowedFromOption,
+                )
+                )
+            }
+            else -> Log.d(
+                TAG,
+                "Encountered unrecognized credential entry ${it.slice.spec?.type}"
+            )
+        }
+    }
+    return result
+}
+val Slice.credentialEntry: CredentialEntry?
+    get() =
+        try {
+            when (spec?.type) {
+                Credential.TYPE_PASSWORD_CREDENTIAL -> PasswordCredentialEntry.fromSlice(this)!!
+                PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
+                    PublicKeyCredentialEntry.fromSlice(this)!!
+
+                else -> CustomCredentialEntry.fromSlice(this)!!
+            }
+        } catch (e: Exception) {
+            // Try CustomCredentialEntry.fromSlice one last time in case the cause was a failed
+            // password / passkey parsing attempt.
+            CustomCredentialEntry.fromSlice(this)
+        }
+
+
+/**
+ * Note: caller required handle empty list due to parsing error.
+ */
+private fun getAuthenticationEntryList(
+    providerId: String,
+    providerDisplayName: String,
+    providerIcon: Drawable,
+    authEntryList: List<AuthenticationEntry>,
+): List<AuthenticationEntryInfo> {
+    val result: MutableList<AuthenticationEntryInfo> = mutableListOf()
+    authEntryList.forEach { entry ->
+        val structuredAuthEntry =
+            AuthenticationAction.fromSlice(entry.slice) ?: return@forEach
+
+        val title: String =
+            structuredAuthEntry.title.toString().ifEmpty { providerDisplayName }
+
+        result.add(
+            AuthenticationEntryInfo(
+            providerId = providerId,
+            entryKey = entry.key,
+            entrySubkey = entry.subkey,
+            pendingIntent = structuredAuthEntry.pendingIntent,
+            fillInIntent = entry.frameworkExtrasIntent,
+            title = title,
+            providerDisplayName = providerDisplayName,
+            icon = providerIcon,
+            isUnlockedAndEmpty = entry.status != AuthenticationEntry.STATUS_LOCKED,
+            isLastUnlocked =
+            entry.status == AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT
+        )
+        )
+    }
+    return result
+}
+
+private fun getRemoteEntry(providerId: String, remoteEntry: Entry?): RemoteEntryInfo? {
+    if (remoteEntry == null) {
+        return null
+    }
+    val structuredRemoteEntry = RemoteEntry.fromSlice(remoteEntry.slice)
+        ?: return null
+    return RemoteEntryInfo(
+        providerId = providerId,
+        entryKey = remoteEntry.key,
+        entrySubkey = remoteEntry.subkey,
+        pendingIntent = structuredRemoteEntry.pendingIntent,
+        fillInIntent = remoteEntry.frameworkExtrasIntent,
+    )
+}
+
+/**
+ * Note: caller required handle empty list due to parsing error.
+ */
+private fun getActionEntryList(
+    providerId: String,
+    actionEntries: List<Entry>,
+    providerIcon: Drawable,
+): List<ActionEntryInfo> {
+    val result: MutableList<ActionEntryInfo> = mutableListOf()
+    actionEntries.forEach {
+        val actionEntryUi = Action.fromSlice(it.slice) ?: return@forEach
+        result.add(
+            ActionEntryInfo(
+            providerId = providerId,
+            entryKey = it.key,
+            entrySubkey = it.subkey,
+            pendingIntent = actionEntryUi.pendingIntent,
+            fillInIntent = it.frameworkExtrasIntent,
+            title = actionEntryUi.title.toString(),
+            icon = providerIcon,
+            subTitle = actionEntryUi.subtitle?.toString(),
+        )
+        )
+    }
+    return result
+}
+
+
+
+private fun getServiceLabelAndIcon(
+    pm: PackageManager,
+    providerFlattenedComponentName: String
+): Pair<String, Drawable>? {
+    var providerLabel: String? = null
+    var providerIcon: Drawable? = null
+    val component = ComponentName.unflattenFromString(providerFlattenedComponentName)
+    if (component == null) {
+        // Test data has only package name not component name.
+        // For test data usage only.
+        try {
+            val pkgInfo = if (Flags.instantAppsEnabled()) {
+                getPackageInfo(pm, providerFlattenedComponentName)
+            } else {
+                pm.getPackageInfo(
+                    providerFlattenedComponentName,
+                    PackageManager.PackageInfoFlags.of(0)
+                )
+            }
+            val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
+            providerLabel =
+                applicationInfo.loadSafeLabel(
+                    pm, 0f,
+                    TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
+                ).toString()
+            providerIcon = applicationInfo.loadIcon(pm)
+        } catch (e: Exception) {
+            Log.e(TAG, "Provider package info not found", e)
+        }
+    } else {
+        try {
+            val si = pm.getServiceInfo(component, PackageManager.ComponentInfoFlags.of(0))
+            providerLabel = si.loadSafeLabel(
+                pm, 0f,
+                TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
+            ).toString()
+            providerIcon = si.loadIcon(pm)
+        } catch (e: PackageManager.NameNotFoundException) {
+            Log.e(TAG, "Provider service info not found", e)
+            // Added for mdoc use case where the provider may not need to register a service and
+            // instead only relies on the registration api.
+            try {
+                val pkgInfo = if (Flags.instantAppsEnabled()) {
+                    getPackageInfo(pm, providerFlattenedComponentName)
+                } else {
+                    pm.getPackageInfo(
+                        component.packageName,
+                        PackageManager.PackageInfoFlags.of(0)
+                    )
+                }
+                val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
+                providerLabel =
+                    applicationInfo.loadSafeLabel(
+                        pm, 0f,
+                        TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
+                    ).toString()
+                providerIcon = applicationInfo.loadIcon(pm)
+            } catch (e: Exception) {
+                Log.e(TAG, "Provider package info not found", e)
+            }
+        }
+    }
+    return if (providerLabel == null || providerIcon == null) {
+        Log.d(
+            TAG,
+            "Failed to load provider label/icon for provider $providerFlattenedComponentName"
+        )
+        null
+    } else {
+        Pair(providerLabel, providerIcon)
+    }
+}
+
+private fun getPackageInfo(
+    pm: PackageManager,
+    packageName: String
+): PackageInfo {
+    val packageManagerFlags = PackageManager.MATCH_INSTANT
+
+    return pm.getPackageInfo(
+        packageName,
+        PackageManager.PackageInfoFlags.of(
+            (packageManagerFlags).toLong())
+    )
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/PasswordKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/PasswordKtx.kt
deleted file mode 100644
index 3471070..0000000
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/PasswordKtx.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2023 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.0N
- *
- * 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.credentialmanager.ktx
-
-import androidx.activity.result.IntentSenderRequest
-import com.android.credentialmanager.IS_AUTO_SELECTED_KEY
-import com.android.credentialmanager.model.Password
-
-fun Password.getIntentSenderRequest(
-    isAutoSelected: Boolean = false
-): IntentSenderRequest {
-    val entryIntent = entry.frameworkExtrasIntent
-    entryIntent?.putExtra(IS_AUTO_SELECTED_KEY, isAutoSelected)
-
-    return IntentSenderRequest.Builder(
-        pendingIntent = passwordCredentialEntry.pendingIntent
-    ).setFillInIntent(entryIntent).build()
-}
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/mapper/RequestGetMapper.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/mapper/RequestGetMapper.kt
index d4bca2a..f1f1f7c 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/mapper/RequestGetMapper.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/mapper/RequestGetMapper.kt
@@ -16,48 +16,18 @@
 
 package com.android.credentialmanager.mapper
 
+import android.content.Context
 import android.content.Intent
-import android.credentials.ui.Entry
-import androidx.credentials.provider.PasswordCredentialEntry
-import com.android.credentialmanager.factory.fromSlice
 import com.android.credentialmanager.ktx.getCredentialProviderDataList
 import com.android.credentialmanager.ktx.requestInfo
 import com.android.credentialmanager.ktx.resultReceiver
-import com.android.credentialmanager.model.Password
+import com.android.credentialmanager.ktx.toProviderList
 import com.android.credentialmanager.model.Request
-import com.google.common.collect.ImmutableList
-import com.google.common.collect.ImmutableMap
 
-fun Intent.toGet(): Request.Get {
-    val credentialEntries = mutableListOf<Pair<String, Entry>>()
-    for (providerData in getCredentialProviderDataList) {
-        for (credentialEntry in providerData.credentialEntries) {
-            credentialEntries.add(
-                Pair(providerData.providerFlattenedComponentName, credentialEntry)
-            )
-        }
-    }
-
-    val passwordEntries = mutableListOf<Password>()
-    for ((providerId, entry) in credentialEntries) {
-        val slice = fromSlice(entry.slice)
-        if (slice is PasswordCredentialEntry) {
-            passwordEntries.add(
-                Password(
-                    providerId = providerId,
-                    entry = entry,
-                    passwordCredentialEntry = slice
-                )
-            )
-        }
-    }
-
+fun Intent.toGet(context: Context): Request.Get {
     return Request.Get(
         token = requestInfo?.token,
-        resultReceiver = this.resultReceiver,
-        providers = ImmutableMap.copyOf(
-            getCredentialProviderDataList.associateBy { it.providerFlattenedComponentName }
-        ),
-        passwordEntries = ImmutableList.copyOf(passwordEntries)
+        resultReceiver = resultReceiver,
+        providerInfos = getCredentialProviderDataList.toProviderList(context)
     )
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/CredentialType.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialType.kt
similarity index 93%
rename from packages/CredentialManager/src/com/android/credentialmanager/common/CredentialType.kt
rename to packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialType.kt
index cc92f60..3f85192 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/CredentialType.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialType.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model
 
 enum class CredentialType {
     UNKNOWN, PASSKEY, PASSWORD,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/EntryInfo.kt
similarity index 92%
rename from packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
rename to packages/CredentialManager/shared/src/com/android/credentialmanager/model/EntryInfo.kt
index ee36989..6d59f11 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/EntryInfo.kt
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model
 
 import android.app.PendingIntent
 import android.content.Intent
 
-open class BaseEntry (
+open class EntryInfo (
     val providerId: String,
     val entryKey: String,
     val entrySubkey: String,
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/Password.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/Password.kt
deleted file mode 100644
index 2fe4fd5..0000000
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/Password.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2023 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.0N
- *
- * 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.credentialmanager.model
-
-import android.credentials.ui.Entry
-import androidx.credentials.provider.PasswordCredentialEntry
-
-data class Password(
-    val providerId: String,
-    val entry: Entry,
-    val passwordCredentialEntry: PasswordCredentialEntry,
-)
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/Request.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/Request.kt
index 2289ed7..7636462 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/Request.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/Request.kt
@@ -16,11 +16,9 @@
 
 package com.android.credentialmanager.model
 
-import android.credentials.ui.ProviderData
 import android.os.IBinder
 import android.os.ResultReceiver
-import com.google.common.collect.ImmutableList
-import com.google.common.collect.ImmutableMap
+import com.android.credentialmanager.model.get.ProviderInfo
 
 /**
  * Represents the request made by the CredentialManager API.
@@ -51,8 +49,7 @@
     data class Get(
         override val token: IBinder?,
         val resultReceiver: ResultReceiver?,
-        val providers: ImmutableMap<String, ProviderData>,
-        val passwordEntries: ImmutableList<Password>,
+        val providerInfos: List<ProviderInfo>,
     ) : Request(token)
     /**
      * Request to start the create credentials flow.
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/CreateOptionInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/CreateOptionInfo.kt
new file mode 100644
index 0000000..d6189eb
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/CreateOptionInfo.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 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.credentialmanager.model.creation
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import com.android.credentialmanager.model.EntryInfo
+import java.time.Instant
+
+class CreateOptionInfo(
+    providerId: String,
+    entryKey: String,
+    entrySubkey: String,
+    pendingIntent: PendingIntent?,
+    fillInIntent: Intent?,
+    val userProviderDisplayName: String,
+    val profileIcon: Drawable?,
+    val passwordCount: Int?,
+    val passkeyCount: Int?,
+    val totalCredentialCount: Int?,
+    val lastUsedTime: Instant,
+    val footerDescription: String?,
+    val allowAutoSelect: Boolean,
+) : EntryInfo(
+    providerId,
+    entryKey,
+    entrySubkey,
+    pendingIntent,
+    fillInIntent,
+    shouldTerminateUiUponSuccessfulProviderResult = true,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/RemoteInfo.kt
similarity index 61%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
copy to packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/RemoteInfo.kt
index ee36989..7ee50d7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/RemoteInfo.kt
@@ -14,16 +14,23 @@
  * limitations under the License.
  */
 
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model.creation
 
 import android.app.PendingIntent
 import android.content.Intent
+import com.android.credentialmanager.model.EntryInfo
 
-open class BaseEntry (
-    val providerId: String,
-    val entryKey: String,
-    val entrySubkey: String,
-    val pendingIntent: PendingIntent?,
-    val fillInIntent: Intent?,
-    val shouldTerminateUiUponSuccessfulProviderResult: Boolean,
+class RemoteInfo(
+    providerId: String,
+    entryKey: String,
+    entrySubkey: String,
+    pendingIntent: PendingIntent?,
+    fillInIntent: Intent?,
+) : EntryInfo(
+    providerId,
+    entryKey,
+    entrySubkey,
+    pendingIntent,
+    fillInIntent,
+    shouldTerminateUiUponSuccessfulProviderResult = true,
 )
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/ActionEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/ActionEntryInfo.kt
new file mode 100644
index 0000000..d9eee86
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/ActionEntryInfo.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 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.credentialmanager.model.get
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import com.android.credentialmanager.model.EntryInfo
+
+class ActionEntryInfo(
+    providerId: String,
+    entryKey: String,
+    entrySubkey: String,
+    pendingIntent: PendingIntent?,
+    fillInIntent: Intent?,
+    val title: String,
+    val icon: Drawable,
+    val subTitle: String?,
+) : EntryInfo(
+    providerId,
+    entryKey,
+    entrySubkey,
+    pendingIntent,
+    fillInIntent,
+    shouldTerminateUiUponSuccessfulProviderResult = true,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/AuthenticationEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/AuthenticationEntryInfo.kt
new file mode 100644
index 0000000..01c394f
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/AuthenticationEntryInfo.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 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.credentialmanager.model.get
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import com.android.credentialmanager.model.EntryInfo
+
+class AuthenticationEntryInfo(
+    providerId: String,
+    entryKey: String,
+    entrySubkey: String,
+    pendingIntent: PendingIntent?,
+    fillInIntent: Intent?,
+    val title: String,
+    val providerDisplayName: String,
+    val icon: Drawable,
+    // The entry had been unlocked and turned out to be empty. Used to determine whether to
+    // show "Tap to unlock" or "No sign-in info" for this entry.
+    val isUnlockedAndEmpty: Boolean,
+    // True if the entry was the last one unlocked. Used to show the no sign-in info snackbar.
+    val isLastUnlocked: Boolean,
+) : EntryInfo(
+    providerId,
+    entryKey, entrySubkey,
+    pendingIntent,
+    fillInIntent,
+    shouldTerminateUiUponSuccessfulProviderResult = false,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
new file mode 100644
index 0000000..9725881
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.credentialmanager.model.get
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.EntryInfo
+import java.time.Instant
+
+class CredentialEntryInfo(
+    providerId: String,
+    entryKey: String,
+    entrySubkey: String,
+    pendingIntent: PendingIntent?,
+    fillInIntent: Intent?,
+    /** Type of this credential used for sorting. Not localized so must not be directly displayed. */
+    val credentialType: CredentialType,
+    /** Localized type value of this credential used for display purpose. */
+    val credentialTypeDisplayName: String,
+    val providerDisplayName: String,
+    val userName: String,
+    val displayName: String?,
+    val icon: Drawable?,
+    val shouldTintIcon: Boolean,
+    val lastUsedTimeMillis: Instant?,
+    val isAutoSelectable: Boolean,
+) : EntryInfo(
+    providerId,
+    entryKey,
+    entrySubkey,
+    pendingIntent,
+    fillInIntent,
+    shouldTerminateUiUponSuccessfulProviderResult = true,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/ProviderInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/ProviderInfo.kt
new file mode 100644
index 0000000..6da4146
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/ProviderInfo.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.credentialmanager.model.get
+
+import android.graphics.drawable.Drawable
+
+data class ProviderInfo(
+    /**
+     * Unique id (component name) of this provider.
+     * Not for display purpose - [displayName] should be used for ui rendering.
+     */
+    val id: String,
+    val icon: Drawable,
+    val displayName: String,
+    val credentialEntryList: List<CredentialEntryInfo>,
+    val authenticationEntryList: List<AuthenticationEntryInfo>,
+    val remoteEntry: RemoteEntryInfo?,
+    val actionEntryList: List<ActionEntryInfo>,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/RemoteEntryInfo.kt
similarity index 61%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
copy to packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/RemoteEntryInfo.kt
index ee36989..a68bf74 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/RemoteEntryInfo.kt
@@ -14,16 +14,23 @@
  * limitations under the License.
  */
 
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model.get
 
 import android.app.PendingIntent
 import android.content.Intent
+import com.android.credentialmanager.model.EntryInfo
 
-open class BaseEntry (
-    val providerId: String,
-    val entryKey: String,
-    val entrySubkey: String,
-    val pendingIntent: PendingIntent?,
-    val fillInIntent: Intent?,
-    val shouldTerminateUiUponSuccessfulProviderResult: Boolean,
+class RemoteEntryInfo(
+    providerId: String,
+    entryKey: String,
+    entrySubkey: String,
+    pendingIntent: PendingIntent?,
+    fillInIntent: Intent?,
+) : EntryInfo(
+    providerId,
+    entryKey,
+    entrySubkey,
+    pendingIntent,
+    fillInIntent,
+    shouldTerminateUiUponSuccessfulProviderResult = true,
 )
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index bce86c4..6c5a984 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -28,7 +28,7 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.lifecycle.ViewModel
-import com.android.credentialmanager.common.BaseEntry
+import com.android.credentialmanager.model.EntryInfo
 import com.android.credentialmanager.common.Constants
 import com.android.credentialmanager.common.DialogState
 import com.android.credentialmanager.common.ProviderActivityResult
@@ -47,7 +47,7 @@
 data class UiState(
     val createCredentialUiState: CreateCredentialUiState?,
     val getCredentialUiState: GetCredentialUiState?,
-    val selectedEntry: BaseEntry? = null,
+    val selectedEntry: EntryInfo? = null,
     val providerActivityState: ProviderActivityState = ProviderActivityState.NOT_APPLICABLE,
     val dialogState: DialogState = DialogState.ACTIVE,
     // True if the UI has one and only one auto selectable entry. Its provider activity will be
@@ -115,12 +115,13 @@
         launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
     ) {
         val entry = uiState.selectedEntry
-        if (entry != null && entry.pendingIntent != null) {
+        val pendingIntent = entry?.pendingIntent
+        if (pendingIntent != null) {
             Log.d(Constants.LOG_TAG, "Launching provider activity")
             uiState = uiState.copy(providerActivityState = ProviderActivityState.PENDING)
             val entryIntent = entry.fillInIntent
             entryIntent?.putExtra(Constants.IS_AUTO_SELECTED_KEY, uiState.isAutoSelectFlow)
-            val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
+            val intentSenderRequest = IntentSenderRequest.Builder(pendingIntent)
                 .setFillInIntent(entryIntent).build()
             try {
                 launcher.launch(intentSenderRequest)
@@ -201,7 +202,7 @@
     /**************************************************************************/
     /*****                      Get Flow Callbacks                        *****/
     /**************************************************************************/
-    fun getFlowOnEntrySelected(entry: BaseEntry) {
+    fun getFlowOnEntrySelected(entry: EntryInfo) {
         Log.d(Constants.LOG_TAG, "credential selected: {provider=${entry.providerId}" +
             ", key=${entry.entryKey}, subkey=${entry.entrySubkey}}")
         uiState = if (entry.pendingIntent != null) {
@@ -363,7 +364,7 @@
         )
     }
 
-    fun createFlowOnEntrySelected(selectedEntry: BaseEntry) {
+    fun createFlowOnEntrySelected(selectedEntry: EntryInfo) {
         val providerId = selectedEntry.providerId
         val entryKey = selectedEntry.entryKey
         val entrySubkey = selectedEntry.entrySubkey
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index f0fa6c5..fc3970d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -16,13 +16,10 @@
 
 package com.android.credentialmanager
 
-import android.app.slice.Slice
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
-import android.credentials.Credential.TYPE_PASSWORD_CREDENTIAL
-import android.credentials.ui.AuthenticationEntry
 import android.credentials.ui.CreateCredentialProviderData
 import android.credentials.ui.DisabledProviderData
 import android.credentials.ui.Entry
@@ -32,36 +29,26 @@
 import android.text.TextUtils
 import android.util.Log
 import com.android.credentialmanager.common.Constants
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.CredentialType
 import com.android.credentialmanager.createflow.ActiveEntry
 import com.android.credentialmanager.createflow.CreateCredentialUiState
-import com.android.credentialmanager.createflow.CreateOptionInfo
+import com.android.credentialmanager.model.creation.CreateOptionInfo
 import com.android.credentialmanager.createflow.CreateScreenState
 import com.android.credentialmanager.createflow.DisabledProviderInfo
 import com.android.credentialmanager.createflow.EnabledProviderInfo
-import com.android.credentialmanager.createflow.RemoteInfo
+import com.android.credentialmanager.model.creation.RemoteInfo
 import com.android.credentialmanager.createflow.RequestDisplayInfo
-import com.android.credentialmanager.getflow.ActionEntryInfo
-import com.android.credentialmanager.getflow.AuthenticationEntryInfo
-import com.android.credentialmanager.getflow.CredentialEntryInfo
-import com.android.credentialmanager.getflow.ProviderInfo
-import com.android.credentialmanager.getflow.RemoteEntryInfo
-import com.android.credentialmanager.getflow.TopBrandingContent
+import com.android.credentialmanager.model.get.ProviderInfo
+import com.android.credentialmanager.ktx.toProviderList
 import androidx.credentials.CreateCredentialRequest
 import androidx.credentials.CreateCustomCredentialRequest
 import androidx.credentials.CreatePasswordRequest
 import androidx.credentials.CreatePublicKeyCredentialRequest
-import androidx.credentials.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
-import androidx.credentials.provider.Action
-import androidx.credentials.provider.AuthenticationAction
 import androidx.credentials.provider.CreateEntry
-import androidx.credentials.provider.CredentialEntry
-import androidx.credentials.provider.CustomCredentialEntry
-import androidx.credentials.provider.PasswordCredentialEntry
-import androidx.credentials.provider.PublicKeyCredentialEntry
 import androidx.credentials.provider.RemoteEntry
 import org.json.JSONObject
 import android.credentials.flags.Flags
+import com.android.credentialmanager.getflow.TopBrandingContent
 import java.time.Instant
 
 
@@ -179,43 +166,7 @@
         fun toProviderList(
             providerDataList: List<GetCredentialProviderData>,
             context: Context,
-        ): List<ProviderInfo> {
-            val providerList: MutableList<ProviderInfo> = mutableListOf()
-            providerDataList.forEach {
-                val providerLabelAndIcon = getServiceLabelAndIcon(
-                    context.packageManager,
-                    it.providerFlattenedComponentName
-                ) ?: return@forEach
-                val (providerLabel, providerIcon) = providerLabelAndIcon
-                providerList.add(
-                    ProviderInfo(
-                        id = it.providerFlattenedComponentName,
-                        icon = providerIcon,
-                        displayName = providerLabel,
-                        credentialEntryList = getCredentialOptionInfoList(
-                            providerId = it.providerFlattenedComponentName,
-                            providerLabel = providerLabel,
-                            credentialEntries = it.credentialEntries,
-                            context = context
-                        ),
-                        authenticationEntryList = getAuthenticationEntryList(
-                            it.providerFlattenedComponentName,
-                            providerLabel,
-                            providerIcon,
-                            it.authenticationEntries),
-                        remoteEntry = getRemoteEntry(
-                            it.providerFlattenedComponentName,
-                            it.remoteEntry
-                        ),
-                        actionEntryList = getActionEntryList(
-                            it.providerFlattenedComponentName, it.actionChips, providerIcon
-                        ),
-                    )
-                )
-            }
-            return providerList
-        }
-
+        ): List<ProviderInfo> = providerDataList.toProviderList(context)
         fun toRequestDisplayInfo(
             requestInfo: RequestInfo?,
             context: Context,
@@ -254,178 +205,6 @@
                 preferTopBrandingContent = preferTopBrandingContent,
             )
         }
-
-
-        /**
-         * Note: caller required handle empty list due to parsing error.
-         */
-        private fun getCredentialOptionInfoList(
-            providerId: String,
-            providerLabel: String,
-            credentialEntries: List<Entry>,
-            context: Context,
-        ): List<CredentialEntryInfo> {
-            val result: MutableList<CredentialEntryInfo> = mutableListOf()
-            credentialEntries.forEach {
-                val credentialEntry = parseCredentialEntryFromSlice(it.slice)
-                when (credentialEntry) {
-                    is PasswordCredentialEntry -> {
-                        result.add(CredentialEntryInfo(
-                            providerId = providerId,
-                            providerDisplayName = providerLabel,
-                            entryKey = it.key,
-                            entrySubkey = it.subkey,
-                            pendingIntent = credentialEntry.pendingIntent,
-                            fillInIntent = it.frameworkExtrasIntent,
-                            credentialType = CredentialType.PASSWORD,
-                            credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
-                            userName = credentialEntry.username.toString(),
-                            displayName = credentialEntry.displayName?.toString(),
-                            icon = credentialEntry.icon.loadDrawable(context),
-                            shouldTintIcon = credentialEntry.isDefaultIcon,
-                            lastUsedTimeMillis = credentialEntry.lastUsedTime,
-                            isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                                credentialEntry.autoSelectAllowedFromOption,
-                        ))
-                    }
-                    is PublicKeyCredentialEntry -> {
-                        result.add(CredentialEntryInfo(
-                            providerId = providerId,
-                            providerDisplayName = providerLabel,
-                            entryKey = it.key,
-                            entrySubkey = it.subkey,
-                            pendingIntent = credentialEntry.pendingIntent,
-                            fillInIntent = it.frameworkExtrasIntent,
-                            credentialType = CredentialType.PASSKEY,
-                            credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
-                            userName = credentialEntry.username.toString(),
-                            displayName = credentialEntry.displayName?.toString(),
-                            icon = credentialEntry.icon.loadDrawable(context),
-                            shouldTintIcon = credentialEntry.isDefaultIcon,
-                            lastUsedTimeMillis = credentialEntry.lastUsedTime,
-                            isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                                credentialEntry.autoSelectAllowedFromOption,
-                        ))
-                    }
-                    is CustomCredentialEntry -> {
-                        result.add(CredentialEntryInfo(
-                            providerId = providerId,
-                            providerDisplayName = providerLabel,
-                            entryKey = it.key,
-                            entrySubkey = it.subkey,
-                            pendingIntent = credentialEntry.pendingIntent,
-                            fillInIntent = it.frameworkExtrasIntent,
-                            credentialType = CredentialType.UNKNOWN,
-                            credentialTypeDisplayName =
-                            credentialEntry.typeDisplayName?.toString().orEmpty(),
-                            userName = credentialEntry.title.toString(),
-                            displayName = credentialEntry.subtitle?.toString(),
-                            icon = credentialEntry.icon.loadDrawable(context),
-                            shouldTintIcon = credentialEntry.isDefaultIcon,
-                            lastUsedTimeMillis = credentialEntry.lastUsedTime,
-                            isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                                credentialEntry.autoSelectAllowedFromOption,
-                        ))
-                    }
-                    else -> Log.d(
-                        Constants.LOG_TAG,
-                        "Encountered unrecognized credential entry ${it.slice.spec?.type}"
-                    )
-                }
-            }
-            return result
-        }
-
-        /**
-         * @hide
-         */
-        fun parseCredentialEntryFromSlice(slice: Slice): CredentialEntry? {
-            try {
-                when (slice.spec?.type) {
-                    TYPE_PASSWORD_CREDENTIAL -> return PasswordCredentialEntry.fromSlice(slice)!!
-                    TYPE_PUBLIC_KEY_CREDENTIAL -> return PublicKeyCredentialEntry.fromSlice(slice)!!
-                    else -> return CustomCredentialEntry.fromSlice(slice)!!
-                }
-            } catch (e: Exception) {
-                // Try CustomCredentialEntry.fromSlice one last time in case the cause was a failed
-                // password / passkey parsing attempt.
-                return CustomCredentialEntry.fromSlice(slice)
-            }
-        }
-
-        /**
-         * Note: caller required handle empty list due to parsing error.
-         */
-        private fun getAuthenticationEntryList(
-            providerId: String,
-            providerDisplayName: String,
-            providerIcon: Drawable,
-            authEntryList: List<AuthenticationEntry>,
-        ): List<AuthenticationEntryInfo> {
-            val result: MutableList<AuthenticationEntryInfo> = mutableListOf()
-            authEntryList.forEach { entry ->
-                val structuredAuthEntry =
-                    AuthenticationAction.fromSlice(entry.slice) ?: return@forEach
-
-                val title: String =
-                    structuredAuthEntry.title.toString().ifEmpty { providerDisplayName }
-
-                result.add(AuthenticationEntryInfo(
-                    providerId = providerId,
-                    entryKey = entry.key,
-                    entrySubkey = entry.subkey,
-                    pendingIntent = structuredAuthEntry.pendingIntent,
-                    fillInIntent = entry.frameworkExtrasIntent,
-                    title = title,
-                    providerDisplayName = providerDisplayName,
-                    icon = providerIcon,
-                    isUnlockedAndEmpty = entry.status != AuthenticationEntry.STATUS_LOCKED,
-                    isLastUnlocked =
-                    entry.status == AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT
-                ))
-            }
-            return result
-        }
-
-        private fun getRemoteEntry(providerId: String, remoteEntry: Entry?): RemoteEntryInfo? {
-            if (remoteEntry == null) {
-                return null
-            }
-            val structuredRemoteEntry = RemoteEntry.fromSlice(remoteEntry.slice)
-                ?: return null
-            return RemoteEntryInfo(
-                providerId = providerId,
-                entryKey = remoteEntry.key,
-                entrySubkey = remoteEntry.subkey,
-                pendingIntent = structuredRemoteEntry.pendingIntent,
-                fillInIntent = remoteEntry.frameworkExtrasIntent,
-            )
-        }
-
-        /**
-         * Note: caller required handle empty list due to parsing error.
-         */
-        private fun getActionEntryList(
-            providerId: String,
-            actionEntries: List<Entry>,
-            providerIcon: Drawable,
-        ): List<ActionEntryInfo> {
-            val result: MutableList<ActionEntryInfo> = mutableListOf()
-            actionEntries.forEach {
-                val actionEntryUi = Action.fromSlice(it.slice) ?: return@forEach
-                result.add(ActionEntryInfo(
-                    providerId = providerId,
-                    entryKey = it.key,
-                    entrySubkey = it.subkey,
-                    pendingIntent = actionEntryUi.pendingIntent,
-                    fillInIntent = it.frameworkExtrasIntent,
-                    title = actionEntryUi.title.toString(),
-                    icon = providerIcon,
-                    subTitle = actionEntryUi.subtitle?.toString(),
-                ))
-            }
-            return result
-        }
     }
 }
 
@@ -686,7 +465,8 @@
             val result: MutableList<CreateOptionInfo> = mutableListOf()
             creationEntries.forEach {
                 val createEntry = CreateEntry.fromSlice(it.slice) ?: return@forEach
-                result.add(CreateOptionInfo(
+                result.add(
+                    CreateOptionInfo(
                     providerId = providerId,
                     entryKey = it.key,
                     entrySubkey = it.subkey,
@@ -705,7 +485,8 @@
                         it.hasHint("androidx.credentials.provider.createEntry.SLICE_HINT_AUTO_" +
                             "SELECT_ALLOWED")
                     }?.text == "true",
-                ))
+                )
+                )
             }
             return result.sortedWith(
                 compareByDescending { it.lastUsedTime }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 281696d..20d2f09 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -48,10 +48,11 @@
 import androidx.credentials.provider.PasswordCredentialEntry
 import androidx.credentials.provider.PublicKeyCredentialEntry
 import com.android.credentialmanager.GetFlowUtils
-import com.android.credentialmanager.getflow.CredentialEntryInfo
+import com.android.credentialmanager.model.get.CredentialEntryInfo
 import com.android.credentialmanager.getflow.ProviderDisplayInfo
-import com.android.credentialmanager.getflow.ProviderInfo
+import com.android.credentialmanager.model.get.ProviderInfo
 import com.android.credentialmanager.getflow.toProviderDisplayInfo
+import com.android.credentialmanager.ktx.credentialEntry
 import org.json.JSONObject
 import java.util.concurrent.Executors
 
@@ -122,8 +123,7 @@
         val entryIconMap: MutableMap<String, Icon> = mutableMapOf()
         candidateProviderDataList.forEach { provider ->
             provider.credentialEntries.forEach { entry ->
-                val credentialEntry = GetFlowUtils.parseCredentialEntryFromSlice(entry.slice)
-                when (credentialEntry) {
+                when (val credentialEntry = entry.slice.credentialEntry) {
                     is PasswordCredentialEntry -> {
                         entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
                     }
@@ -172,11 +172,11 @@
     }
 
     private fun processProvidersForAutofillId(
-            filLRequest: FillRequest,
-            autofillId: AutofillId,
-            providerList: List<ProviderInfo>,
-            entryIconMap: Map<String, Icon>,
-            fillResponseBuilder: FillResponse.Builder
+        filLRequest: FillRequest,
+        autofillId: AutofillId,
+        providerList: List<ProviderInfo>,
+        entryIconMap: Map<String, Icon>,
+        fillResponseBuilder: FillResponse.Builder
     ): Boolean {
         if (providerList.isEmpty()) {
             return false
@@ -200,7 +200,8 @@
         providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@ {
             val primaryEntry = it.sortedCredentialEntryList.first()
             val pendingIntent = primaryEntry.pendingIntent
-            if (pendingIntent == null || primaryEntry.fillInIntent == null) {
+            val fillInIntent = primaryEntry.fillInIntent
+            if (pendingIntent == null || fillInIntent == null) {
                 // FillInIntent will not be null because autofillId was retrieved from it.
                 Log.e(TAG, "PendingIntent was missing from the entry.")
                 return@usernameLoop
@@ -245,7 +246,7 @@
                                             presentationBuilder.build())
                                             .build())
                             .setAuthentication(pendingIntent.intentSender)
-                            .setAuthenticationExtras(primaryEntry.fillInIntent.extras)
+                            .setAuthenticationExtras(fillInIntent.extras)
                             .build())
             datasetAdded = true
         }
@@ -322,8 +323,8 @@
     }
 
     private fun copyProviderInfo(
-            providerInfo: ProviderInfo,
-            credentialList: List<CredentialEntryInfo>
+        providerInfo: ProviderInfo,
+        credentialList: List<CredentialEntryInfo>
     ): ProviderInfo {
         return ProviderInfo(
                 providerInfo.id,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index d45b6f6..14a9165 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -48,8 +48,8 @@
 import androidx.core.graphics.drawable.toBitmap
 import com.android.credentialmanager.CredentialSelectorViewModel
 import com.android.credentialmanager.R
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
 import com.android.credentialmanager.common.ProviderActivityState
 import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
 import com.android.credentialmanager.common.ui.ActionButton
@@ -68,6 +68,8 @@
 import com.android.credentialmanager.common.ui.PasskeyBenefitRow
 import com.android.credentialmanager.common.ui.HeadlineText
 import com.android.credentialmanager.logging.CreateCredentialEvent
+import com.android.credentialmanager.model.creation.CreateOptionInfo
+import com.android.credentialmanager.model.creation.RemoteInfo
 import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
 import com.android.internal.logging.UiEventLogger.UiEventEnum
 
@@ -259,15 +261,15 @@
 
 @Composable
 fun MoreOptionsSelectionCard(
-        requestDisplayInfo: RequestDisplayInfo,
-        enabledProviderList: List<EnabledProviderInfo>,
-        disabledProviderList: List<DisabledProviderInfo>?,
-        sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
-        onBackCreationSelectionButtonSelected: () -> Unit,
-        onOptionSelected: (ActiveEntry) -> Unit,
-        onDisabledProvidersSelected: () -> Unit,
-        onRemoteEntrySelected: (BaseEntry) -> Unit,
-        onLog: @Composable (UiEventEnum) -> Unit,
+    requestDisplayInfo: RequestDisplayInfo,
+    enabledProviderList: List<EnabledProviderInfo>,
+    disabledProviderList: List<DisabledProviderInfo>?,
+    sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
+    onBackCreationSelectionButtonSelected: () -> Unit,
+    onOptionSelected: (ActiveEntry) -> Unit,
+    onDisabledProvidersSelected: () -> Unit,
+    onRemoteEntrySelected: (EntryInfo) -> Unit,
+    onLog: @Composable (UiEventEnum) -> Unit,
 ) {
     SheetContainerCard(topAppBar = {
         MoreOptionTopAppBar(
@@ -378,14 +380,14 @@
 
 @Composable
 fun CreationSelectionCard(
-        requestDisplayInfo: RequestDisplayInfo,
-        enabledProviderList: List<EnabledProviderInfo>,
-        providerInfo: EnabledProviderInfo,
-        createOptionInfo: CreateOptionInfo,
-        onOptionSelected: (BaseEntry) -> Unit,
-        onConfirm: () -> Unit,
-        onMoreOptionsSelected: () -> Unit,
-        onLog: @Composable (UiEventEnum) -> Unit,
+    requestDisplayInfo: RequestDisplayInfo,
+    enabledProviderList: List<EnabledProviderInfo>,
+    providerInfo: EnabledProviderInfo,
+    createOptionInfo: CreateOptionInfo,
+    onOptionSelected: (EntryInfo) -> Unit,
+    onConfirm: () -> Unit,
+    onMoreOptionsSelected: () -> Unit,
+    onLog: @Composable (UiEventEnum) -> Unit,
 ) {
     SheetContainerCard {
         item {
@@ -474,11 +476,11 @@
 
 @Composable
 fun ExternalOnlySelectionCard(
-        requestDisplayInfo: RequestDisplayInfo,
-        activeRemoteEntry: BaseEntry,
-        onOptionSelected: (BaseEntry) -> Unit,
-        onConfirm: () -> Unit,
-        onLog: @Composable (UiEventEnum) -> Unit,
+    requestDisplayInfo: RequestDisplayInfo,
+    activeRemoteEntry: EntryInfo,
+    onOptionSelected: (EntryInfo) -> Unit,
+    onConfirm: () -> Unit,
+    onLog: @Composable (UiEventEnum) -> Unit,
 ) {
     SheetContainerCard {
         item { HeadlineIcon(imageVector = Icons.Outlined.QrCodeScanner) }
@@ -575,17 +577,14 @@
 @Composable
 fun PrimaryCreateOptionRow(
     requestDisplayInfo: RequestDisplayInfo,
-    entryInfo: BaseEntry,
-    onOptionSelected: (BaseEntry) -> Unit
+    entryInfo: EntryInfo,
+    onOptionSelected: (EntryInfo) -> Unit
 ) {
     Entry(
         onClick = { onOptionSelected(entryInfo) },
-        iconImageBitmap =
-        if (entryInfo is CreateOptionInfo && entryInfo.profileIcon != null) {
-            entryInfo.profileIcon.toBitmap().asImageBitmap()
-        } else {
-            requestDisplayInfo.typeIcon.toBitmap().asImageBitmap()
-        },
+        iconImageBitmap = ((entryInfo as? CreateOptionInfo)?.profileIcon
+            ?: requestDisplayInfo.typeIcon)
+            .toBitmap().asImageBitmap(),
         shouldApplyIconImageBitmapTint = !(entryInfo is CreateOptionInfo &&
             entryInfo.profileIcon != null),
         entryHeadlineText = requestDisplayInfo.title,
@@ -627,32 +626,33 @@
         entryThirdLineText =
         if (requestDisplayInfo.type == CredentialType.PASSKEY ||
             requestDisplayInfo.type == CredentialType.PASSWORD) {
-            if (createOptionInfo.passwordCount != null &&
-                createOptionInfo.passkeyCount != null
-            ) {
+            val passwordCount = createOptionInfo.passwordCount
+            val passkeyCount = createOptionInfo.passkeyCount
+            if (passwordCount != null && passkeyCount != null) {
                 stringResource(
                     R.string.more_options_usage_passwords_passkeys,
-                    createOptionInfo.passwordCount,
-                    createOptionInfo.passkeyCount
+                    passwordCount,
+                    passkeyCount
                 )
-            } else if (createOptionInfo.passwordCount != null) {
+            } else if (passwordCount != null) {
                 stringResource(
                     R.string.more_options_usage_passwords,
-                    createOptionInfo.passwordCount
+                    passwordCount
                 )
-            } else if (createOptionInfo.passkeyCount != null) {
+            } else if (passkeyCount != null) {
                 stringResource(
                     R.string.more_options_usage_passkeys,
-                    createOptionInfo.passkeyCount
+                    passkeyCount
                 )
             } else {
                 null
             }
         } else {
-            if (createOptionInfo.totalCredentialCount != null) {
+            val totalCredentialCount = createOptionInfo.totalCredentialCount
+            if (totalCredentialCount != null) {
                 stringResource(
                     R.string.more_options_usage_credentials,
-                    createOptionInfo.totalCredentialCount
+                    totalCredentialCount
                 )
             } else {
                 null
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index e9e8c2e..8b0ba87 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -16,22 +16,21 @@
 
 package com.android.credentialmanager.createflow
 
-import android.app.PendingIntent
-import android.content.Intent
 import android.graphics.drawable.Drawable
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
-import java.time.Instant
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.creation.CreateOptionInfo
+import com.android.credentialmanager.model.creation.RemoteInfo
 
 data class CreateCredentialUiState(
-  val enabledProviders: List<EnabledProviderInfo>,
-  val disabledProviders: List<DisabledProviderInfo>? = null,
-  val currentScreenState: CreateScreenState,
-  val requestDisplayInfo: RequestDisplayInfo,
-  val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
-  val activeEntry: ActiveEntry? = null,
-  val remoteEntry: RemoteInfo? = null,
-  val foundCandidateFromUserDefaultProvider: Boolean,
+    val enabledProviders: List<EnabledProviderInfo>,
+    val disabledProviders: List<DisabledProviderInfo>? = null,
+    val currentScreenState: CreateScreenState,
+    val requestDisplayInfo: RequestDisplayInfo,
+    val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
+    val activeEntry: ActiveEntry? = null,
+    val remoteEntry: RemoteInfo? = null,
+    val foundCandidateFromUserDefaultProvider: Boolean,
 )
 
 internal fun isFlowAutoSelectable(
@@ -75,44 +74,6 @@
   displayName: String,
 ) : ProviderInfo(icon, id, displayName)
 
-class CreateOptionInfo(
-    providerId: String,
-    entryKey: String,
-    entrySubkey: String,
-    pendingIntent: PendingIntent?,
-    fillInIntent: Intent?,
-    val userProviderDisplayName: String,
-    val profileIcon: Drawable?,
-    val passwordCount: Int?,
-    val passkeyCount: Int?,
-    val totalCredentialCount: Int?,
-    val lastUsedTime: Instant,
-    val footerDescription: String?,
-    val allowAutoSelect: Boolean,
-) : BaseEntry(
-    providerId,
-    entryKey,
-    entrySubkey,
-    pendingIntent,
-    fillInIntent,
-    shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
-class RemoteInfo(
-  providerId: String,
-  entryKey: String,
-  entrySubkey: String,
-  pendingIntent: PendingIntent?,
-  fillInIntent: Intent?,
-) : BaseEntry(
-    providerId,
-    entryKey,
-    entrySubkey,
-    pendingIntent,
-    fillInIntent,
-    shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
 data class RequestDisplayInfo(
   val title: String,
   val subtitle: String?,
@@ -131,8 +92,8 @@
  * user selects a different entry on the more option page.
  */
 data class ActiveEntry (
-  val activeProvider: EnabledProviderInfo,
-  val activeEntryInfo: BaseEntry,
+    val activeProvider: EnabledProviderInfo,
+    val activeEntryInfo: EntryInfo,
 )
 
 /** The name of the current screen. */
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 72d030b..4ed84b9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -48,8 +48,9 @@
 import androidx.core.graphics.drawable.toBitmap
 import com.android.credentialmanager.CredentialSelectorViewModel
 import com.android.credentialmanager.R
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.get.ProviderInfo
 import com.android.credentialmanager.common.ProviderActivityState
 import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
 import com.android.credentialmanager.common.ui.ActionButton
@@ -68,6 +69,10 @@
 import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
 import com.android.credentialmanager.common.ui.Snackbar
 import com.android.credentialmanager.logging.GetCredentialEvent
+import com.android.credentialmanager.model.get.ActionEntryInfo
+import com.android.credentialmanager.model.get.AuthenticationEntryInfo
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.get.RemoteEntryInfo
 import com.android.credentialmanager.userAndDisplayNameForPasskey
 import com.android.internal.logging.UiEventLogger.UiEventEnum
 
@@ -175,8 +180,8 @@
     requestDisplayInfo: RequestDisplayInfo,
     providerDisplayInfo: ProviderDisplayInfo,
     providerInfoList: List<ProviderInfo>,
-    activeEntry: BaseEntry?,
-    onEntrySelected: (BaseEntry) -> Unit,
+    activeEntry: EntryInfo?,
+    onEntrySelected: (EntryInfo) -> Unit,
     onConfirm: () -> Unit,
     onMoreOptionSelected: () -> Unit,
     onLog: @Composable (UiEventEnum) -> Unit,
@@ -358,7 +363,7 @@
 fun AllSignInOptionCard(
     providerInfoList: List<ProviderInfo>,
     providerDisplayInfo: ProviderDisplayInfo,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
     onBackButtonClicked: () -> Unit,
     onCancel: () -> Unit,
     onLog: @Composable (UiEventEnum) -> Unit,
@@ -436,7 +441,7 @@
 @Composable
 fun ActionChips(
     providerInfoList: List<ProviderInfo>,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
     isFirstSection: Boolean,
 ) {
     val actionChips = providerInfoList.flatMap { it.actionEntryList }
@@ -460,7 +465,7 @@
 @Composable
 fun RemoteEntryCard(
     remoteEntry: RemoteEntryInfo,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
     isFirstSection: Boolean,
 ) {
     CredentialListSectionHeader(
@@ -486,7 +491,7 @@
 @Composable
 fun LockedCredentials(
     authenticationEntryList: List<AuthenticationEntryInfo>,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
     isFirstSection: Boolean,
 ) {
     CredentialListSectionHeader(
@@ -508,7 +513,7 @@
 @Composable
 fun PerUserNameCredentials(
     perUserNameCredentialEntryList: PerUserNameCredentialEntryList,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
     isFirstSection: Boolean,
 ) {
     CredentialListSectionHeader(
@@ -532,7 +537,7 @@
 @Composable
 fun CredentialEntryRow(
     credentialEntryInfo: CredentialEntryInfo,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
     enforceOneLine: Boolean = false,
     onTextLayout: (TextLayoutResult) -> Unit = {},
 ) {
@@ -571,7 +576,7 @@
 @Composable
 fun AuthenticationEntryRow(
     authenticationEntryInfo: AuthenticationEntryInfo,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
     enforceOneLine: Boolean = false,
 ) {
     Entry(
@@ -596,7 +601,7 @@
 @Composable
 fun ActionEntryRow(
     actionEntryInfo: ActionEntryInfo,
-    onEntrySelected: (BaseEntry) -> Unit,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
     ActionEntry(
         iconImageBitmap = actionEntryInfo.icon.toBitmap().asImageBitmap(),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 447a9d2..46bebc4 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -16,21 +16,21 @@
 
 package com.android.credentialmanager.getflow
 
-import android.app.PendingIntent
-import android.content.Intent
 import android.graphics.drawable.Drawable
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.get.ProviderInfo
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.get.AuthenticationEntryInfo
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.get.RemoteEntryInfo
 import com.android.internal.util.Preconditions
 
-import java.time.Instant
-
 data class GetCredentialUiState(
     val providerInfoList: List<ProviderInfo>,
     val requestDisplayInfo: RequestDisplayInfo,
     val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
     val currentScreenState: GetScreenState = toGetScreenState(providerDisplayInfo),
-    val activeEntry: BaseEntry? = toActiveEntry(providerDisplayInfo),
+    val activeEntry: EntryInfo? = toActiveEntry(providerDisplayInfo),
     val isNoAccount: Boolean = false,
 )
 
@@ -58,20 +58,6 @@
     return null
 }
 
-data class ProviderInfo(
-    /**
-     * Unique id (component name) of this provider.
-     * Not for display purpose - [displayName] should be used for ui rendering.
-     */
-    val id: String,
-    val icon: Drawable,
-    val displayName: String,
-    val credentialEntryList: List<CredentialEntryInfo>,
-    val authenticationEntryList: List<AuthenticationEntryInfo>,
-    val remoteEntry: RemoteEntryInfo?,
-    val actionEntryList: List<ActionEntryInfo>,
-)
-
 /** Display-centric data structure derived from the [ProviderInfo]. This abstraction is not grouping
  *  by the provider id but instead focuses on structures convenient for display purposes. */
 data class ProviderDisplayInfo(
@@ -84,87 +70,6 @@
     val remoteEntry: RemoteEntryInfo?
 )
 
-class CredentialEntryInfo(
-    providerId: String,
-    entryKey: String,
-    entrySubkey: String,
-    pendingIntent: PendingIntent?,
-    fillInIntent: Intent?,
-    /** Type of this credential used for sorting. Not localized so must not be directly displayed. */
-    val credentialType: CredentialType,
-    /** Localized type value of this credential used for display purpose. */
-    val credentialTypeDisplayName: String,
-    val providerDisplayName: String,
-    val userName: String,
-    val displayName: String?,
-    val icon: Drawable?,
-    val shouldTintIcon: Boolean,
-    val lastUsedTimeMillis: Instant?,
-    val isAutoSelectable: Boolean,
-) : BaseEntry(
-    providerId,
-    entryKey,
-    entrySubkey,
-    pendingIntent,
-    fillInIntent,
-    shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
-class AuthenticationEntryInfo(
-    providerId: String,
-    entryKey: String,
-    entrySubkey: String,
-    pendingIntent: PendingIntent?,
-    fillInIntent: Intent?,
-    val title: String,
-    val providerDisplayName: String,
-    val icon: Drawable,
-    // The entry had been unlocked and turned out to be empty. Used to determine whether to
-    // show "Tap to unlock" or "No sign-in info" for this entry.
-    val isUnlockedAndEmpty: Boolean,
-    // True if the entry was the last one unlocked. Used to show the no sign-in info snackbar.
-    val isLastUnlocked: Boolean,
-) : BaseEntry(
-    providerId,
-    entryKey, entrySubkey,
-    pendingIntent,
-    fillInIntent,
-    shouldTerminateUiUponSuccessfulProviderResult = false,
-)
-
-class RemoteEntryInfo(
-    providerId: String,
-    entryKey: String,
-    entrySubkey: String,
-    pendingIntent: PendingIntent?,
-    fillInIntent: Intent?,
-) : BaseEntry(
-    providerId,
-    entryKey,
-    entrySubkey,
-    pendingIntent,
-    fillInIntent,
-    shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
-class ActionEntryInfo(
-    providerId: String,
-    entryKey: String,
-    entrySubkey: String,
-    pendingIntent: PendingIntent?,
-    fillInIntent: Intent?,
-    val title: String,
-    val icon: Drawable,
-    val subTitle: String?,
-) : BaseEntry(
-    providerId,
-    entryKey,
-    entrySubkey,
-    pendingIntent,
-    fillInIntent,
-    shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
 data class RequestDisplayInfo(
     val appName: String,
     val preferImmediatelyAvailableCredentials: Boolean,
@@ -218,8 +123,8 @@
     val remoteEntryList = mutableListOf<RemoteEntryInfo>()
     providerInfoList.forEach { providerInfo ->
         authenticationEntryList.addAll(providerInfo.authenticationEntryList)
-        if (providerInfo.remoteEntry != null) {
-            remoteEntryList.add(providerInfo.remoteEntry)
+        providerInfo.remoteEntry?.let {
+            remoteEntryList.add(it)
         }
         // There can only be at most one remote entry
         Preconditions.checkState(remoteEntryList.size <= 1)
@@ -260,11 +165,11 @@
 
 private fun toActiveEntry(
     providerDisplayInfo: ProviderDisplayInfo,
-): BaseEntry? {
+): EntryInfo? {
     val sortedUserNameToCredentialEntryList =
         providerDisplayInfo.sortedUserNameToCredentialEntryList
     val authenticationEntryList = providerDisplayInfo.authenticationEntryList
-    var activeEntry: BaseEntry? = null
+    var activeEntry: EntryInfo? = null
     if (sortedUserNameToCredentialEntryList
             .size == 1 && authenticationEntryList.isEmpty()
     ) {
@@ -302,17 +207,18 @@
                 return 1
             }
         }
-
+        val p0LastUsedTimeMillis = p0.lastUsedTimeMillis
+        val p1LastUsedTimeMillis = p1.lastUsedTimeMillis
         // Then order by last used timestamp
-        if (p0.lastUsedTimeMillis != null && p1.lastUsedTimeMillis != null) {
-            if (p0.lastUsedTimeMillis < p1.lastUsedTimeMillis) {
+        if (p0LastUsedTimeMillis != null && p1LastUsedTimeMillis != null) {
+            if (p0LastUsedTimeMillis < p1LastUsedTimeMillis) {
                 return 1
-            } else if (p0.lastUsedTimeMillis > p1.lastUsedTimeMillis) {
+            } else if (p0LastUsedTimeMillis > p1LastUsedTimeMillis) {
                 return -1
             }
-        } else if (p0.lastUsedTimeMillis != null) {
+        } else if (p0LastUsedTimeMillis != null) {
             return -1
-        } else if (p1.lastUsedTimeMillis != null) {
+        } else if (p1LastUsedTimeMillis != null) {
             return 1
         }
         return 0
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/di/AppModule.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/di/AppModule.kt
index 6ededf3..d8a6019 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/di/AppModule.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/di/AppModule.kt
@@ -1,29 +1,20 @@
 package com.android.credentialmanager.di
 
-import android.content.Context
-import android.content.pm.PackageManager
 import com.android.credentialmanager.client.CredentialManagerClient
 import com.android.credentialmanager.client.impl.CredentialManagerClientImpl
+import dagger.Binds
 import dagger.Module
-import dagger.Provides
 import dagger.hilt.InstallIn
-import dagger.hilt.android.qualifiers.ApplicationContext
 import dagger.hilt.components.SingletonComponent
 import javax.inject.Singleton
 
 @Module
 @InstallIn(SingletonComponent::class)
-internal object AppModule {
-    @Provides
+abstract class AppModule {
+    @Binds
     @Singleton
-    @JvmStatic
-    fun providePackageManager(@ApplicationContext context: Context): PackageManager =
-        context.packageManager
-
-    @Provides
-    @Singleton
-    @JvmStatic
-    fun provideCredentialManagerClient(packageManager: PackageManager): CredentialManagerClient =
-        CredentialManagerClientImpl(packageManager)
+    abstract fun provideCredentialManagerClient(
+        client: CredentialManagerClientImpl
+    ): CredentialManagerClient
 }
 
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
index f2f878e..14b992a 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
@@ -23,8 +23,8 @@
     // TODO: b/301206470 returning a hard coded state for MVP
     if (true) return CredentialSelectorUiState.Get.SingleProviderSinglePassword
 
-    return if (providers.size == 1) {
-        if (passwordEntries.size == 1) {
+    return if (providerInfos.size == 1) {
+        if (providerInfos.first().credentialEntryList.size == 1) {
             CredentialSelectorUiState.Get.SingleProviderSinglePassword
         } else {
             TODO() // b/301206470 - Implement other get flows
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
index c28df3e8..b64f581 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
@@ -76,7 +76,9 @@
             }
 
             SideEffect {
-                launcher.launch(state.intentSenderRequest)
+                state.intentSenderRequest?.let {
+                    launcher.launch(it)
+                }
             }
         }
 
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
index fb72c54..26bee1f 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
@@ -26,9 +26,9 @@
 import androidx.lifecycle.viewModelScope
 import com.android.credentialmanager.TAG
 import com.android.credentialmanager.ktx.getIntentSenderRequest
-import com.android.credentialmanager.model.Password
 import com.android.credentialmanager.model.Request
 import com.android.credentialmanager.client.CredentialManagerClient
+import com.android.credentialmanager.model.get.CredentialEntryInfo
 import com.android.credentialmanager.ui.model.PasswordUiModel
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -44,7 +44,7 @@
     private var initializeCalled = false
 
     private lateinit var requestGet: Request.Get
-    private lateinit var password: Password
+    private lateinit var entryInfo: CredentialEntryInfo
 
     private val _uiState =
         MutableStateFlow<SinglePasswordScreenUiState>(SinglePasswordScreenUiState.Idle)
@@ -63,14 +63,15 @@
                 _uiState.value = SinglePasswordScreenUiState.Error
             } else {
                 requestGet = request
-                if (requestGet.passwordEntries.isEmpty()) {
+
+                if (requestGet.providerInfos.all { it.credentialEntryList.isEmpty() }) {
                     Log.d(TAG, "Empty passwordEntries")
                     _uiState.value = SinglePasswordScreenUiState.Error
                 } else {
-                    password = requestGet.passwordEntries.first()
+                    entryInfo = requestGet.providerInfos.first().credentialEntryList.first()
                     _uiState.value = SinglePasswordScreenUiState.Loaded(
                         PasswordUiModel(
-                            email = password.passwordCredentialEntry.username.toString(),
+                            email = entryInfo.userName,
                         )
                     )
                 }
@@ -84,7 +85,7 @@
 
     fun onOKClick() {
         _uiState.value = SinglePasswordScreenUiState.PasswordSelected(
-            intentSenderRequest = password.getIntentSenderRequest()
+            intentSenderRequest = entryInfo.getIntentSenderRequest()
         )
     }
 
@@ -94,9 +95,9 @@
     ) {
         val userSelectionDialogResult = UserSelectionDialogResult(
             requestGet.token,
-            password.providerId,
-            password.entry.key,
-            password.entry.subkey,
+            entryInfo.providerId,
+            entryInfo.entryKey,
+            entryInfo.entrySubkey,
             if (resultCode != null) ProviderPendingIntentResponse(resultCode, resultData) else null
         )
         credentialManagerClient.sendResult(userSelectionDialogResult)
@@ -108,7 +109,7 @@
     data object Idle : SinglePasswordScreenUiState()
     data class Loaded(val passwordUiModel: PasswordUiModel) : SinglePasswordScreenUiState()
     data class PasswordSelected(
-        val intentSenderRequest: IntentSenderRequest
+        val intentSenderRequest: IntentSenderRequest?
     ) : SinglePasswordScreenUiState()
 
     data object Cancel : SinglePasswordScreenUiState()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index a2e930c..9f46e22 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -287,6 +287,10 @@
             return
         }
 
+        if (smartSpaceView != null) {
+            parentView.removeView(smartSpaceView)
+        }
+
         smartSpaceView = lockscreenSmartspaceController.buildAndConnectDateView(parentView)
 
         val topPadding: Int =
@@ -362,12 +366,13 @@
             ),
         )
 
+        setUpUdfps(previewContext, rootView)
+
         disposables.add(
             PreviewKeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) {
                 if (keyguardBottomAreaRefactor()) {
                     setupShortcuts(keyguardRootView)
                 }
-                setUpUdfps(previewContext, rootView)
 
                 if (!shouldHideClock) {
                     setUpClock(previewContext, rootView)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
index bbba19d..87df180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
@@ -73,7 +73,11 @@
 
     /** Callback to be notified about device posture changes. */
     interface Callback {
-        /** Called when the posture changes. */
+        /**
+         * Called when the posture changes. If there are multiple active displays ("concurrent"),
+         * this will report the physical posture of the device (also known as the base device
+         * state).
+         */
         void onPostureChanged(@DevicePostureInt int posture);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
index 8f1ac81..422aa4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -39,8 +39,11 @@
 /** Implementation of {@link DevicePostureController} using the DeviceStateManager. */
 @SysUISingleton
 public class DevicePostureControllerImpl implements DevicePostureController {
+    /** From androidx.window.common.COMMON_STATE_USE_BASE_STATE */
+    private static final int COMMON_STATE_USE_BASE_STATE = 1000;
     private final List<Callback> mListeners = new ArrayList<>();
     private int mCurrentDevicePosture = DEVICE_POSTURE_UNKNOWN;
+    private int mCurrentBasePosture = DEVICE_POSTURE_UNKNOWN;
 
     private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
 
@@ -73,16 +76,32 @@
             mDeviceStateToPostureMap.put(deviceState, posture);
         }
 
-        deviceStateManager.registerCallback(executor, state -> {
-            Assert.isMainThread();
-            mCurrentDevicePosture =
-                    mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
+        deviceStateManager.registerCallback(executor, new DeviceStateManager.DeviceStateCallback() {
+            @Override
+            public void onStateChanged(int state) {
+                Assert.isMainThread();
+                mCurrentDevicePosture =
+                        mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
+                sendUpdatePosture();
+            }
 
-            ListenersTracing.INSTANCE.forEachTraced(mListeners, "DevicePostureControllerImpl",
+            @Override
+            public void onBaseStateChanged(int state) {
+                Assert.isMainThread();
+                mCurrentBasePosture = mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
+
+                if (useBaseState()) {
+                    sendUpdatePosture();
+                }
+            }
+
+            private void sendUpdatePosture() {
+                ListenersTracing.INSTANCE.forEachTraced(mListeners, "DevicePostureControllerImpl",
                     l -> {
-                        l.onPostureChanged(mCurrentDevicePosture);
+                        l.onPostureChanged(getDevicePosture());
                         return Unit.INSTANCE;
                     });
+            }
         });
     }
 
@@ -100,6 +119,14 @@
 
     @Override
     public int getDevicePosture() {
-        return mCurrentDevicePosture;
+        if (useBaseState()) {
+            return mCurrentBasePosture;
+        } else {
+            return mCurrentDevicePosture;
+        }
+    }
+
+    private boolean useBaseState() {
+        return mCurrentDevicePosture == COMMON_STATE_USE_BASE_STATE;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index e576f36..279e5ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -16,6 +16,7 @@
 
 import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener;
+import com.android.systemui.util.annotations.WeaklyReferencedCallback;
 
 public interface FlashlightController extends CallbackController<FlashlightListener>, Dumpable {
 
@@ -24,6 +25,7 @@
     boolean isAvailable();
     boolean isEnabled();
 
+    @WeaklyReferencedCallback
     public interface FlashlightListener {
 
         /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
new file mode 100644
index 0000000..ce47170
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.hardware.devicestate.DeviceStateManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableResources
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_FLIPPED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
+import com.android.systemui.statusbar.policy.DevicePostureController.SUPPORTED_POSTURES_SIZE
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class DevicePostureControllerImplTest : SysuiTestCase() {
+    private val useBaseStateDeviceState = SUPPORTED_POSTURES_SIZE
+    private val deviceStateToPostureMapping =
+        arrayOf(
+            "$DEVICE_POSTURE_UNKNOWN:$DEVICE_POSTURE_UNKNOWN",
+            "$DEVICE_POSTURE_CLOSED:$DEVICE_POSTURE_CLOSED",
+            "$DEVICE_POSTURE_HALF_OPENED:$DEVICE_POSTURE_HALF_OPENED",
+            "$DEVICE_POSTURE_OPENED:$DEVICE_POSTURE_OPENED",
+            "$DEVICE_POSTURE_FLIPPED:$DEVICE_POSTURE_FLIPPED",
+            "$useBaseStateDeviceState:1000"
+        )
+    @Mock private lateinit var deviceStateManager: DeviceStateManager
+    @Captor
+    private lateinit var deviceStateCallback: ArgumentCaptor<DeviceStateManager.DeviceStateCallback>
+
+    private lateinit var mainExecutor: FakeExecutor
+    private lateinit var testableResources: TestableResources
+    private lateinit var underTest: DevicePostureControllerImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        mainExecutor = FakeExecutor(FakeSystemClock())
+        testableResources = context.getOrCreateTestableResources()
+        testableResources.addOverride(
+            com.android.internal.R.array.config_device_state_postures,
+            deviceStateToPostureMapping
+        )
+        underTest =
+            DevicePostureControllerImpl(
+                context,
+                deviceStateManager,
+                mainExecutor,
+            )
+        verifyRegistersForDeviceStateCallback()
+    }
+
+    @Test
+    fun testPostureChanged_updates() {
+        var posture = -1
+        underTest.addCallback { posture = it }
+
+        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_UNKNOWN)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_UNKNOWN)
+
+        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_CLOSED)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)
+
+        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
+
+        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_OPENED)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_OPENED)
+
+        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_FLIPPED)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_FLIPPED)
+    }
+
+    @Test
+    fun testPostureChanged_useBaseUpdate() {
+        var posture = -1
+        underTest.addCallback { posture = it }
+
+        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
+
+        // base state change doesn't change the posture
+        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
+
+        // WHEN the display state maps to using the base state, then posture updates
+        deviceStateCallback.value.onStateChanged(useBaseStateDeviceState)
+        assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)
+    }
+
+    @Test
+    fun baseStateChanges_doesNotUpdatePosture() {
+        var numPostureChanges = 0
+        underTest.addCallback { numPostureChanges++ }
+
+        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+        assertThat(numPostureChanges).isEqualTo(1)
+
+        // base state changes doesn't send another posture update since the device state isn't
+        // useBaseStateDeviceState
+        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
+        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_HALF_OPENED)
+        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_FLIPPED)
+        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_OPENED)
+        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_UNKNOWN)
+        assertThat(numPostureChanges).isEqualTo(1)
+    }
+
+    private fun verifyRegistersForDeviceStateCallback() {
+        verify(deviceStateManager).registerCallback(eq(mainExecutor), deviceStateCallback.capture())
+    }
+}
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index c70c171..79bfa44 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -1,5 +1,8 @@
 # Ravenwood "policy" file for framework-minus-apex.
 
+# Keep all AIDL interfaces
+class :aidl stubclass
+
 # Collections
 class android.util.ArrayMap stubclass
 class android.util.ArraySet stubclass
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b5e8c84..4b10111 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -5580,6 +5580,8 @@
 
     @Override
     public void injectInputEventToInputFilter(InputEvent event) {
+        mSecurityPolicy.enforceCallingPermission(Manifest.permission.INJECT_EVENTS,
+                "injectInputEventToInputFilter");
         synchronized (mLock) {
             final long endMillis =
                     SystemClock.uptimeMillis() + WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS;
diff --git a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java
index 5665ad5..d089b05 100644
--- a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java
+++ b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java
@@ -27,14 +27,14 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.util.ArraySet;
+import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
-import java.util.Set;
+import java.util.Map;
 
 /**
  * Manages the registration and removal of virtual camera from the server side.
@@ -47,10 +47,13 @@
     private static final String VIRTUAL_CAMERA_SERVICE_NAME = "virtual_camera";
     private static final String TAG = "VirtualCameraController";
 
+    private final Object mServiceLock = new Object();
+
+    @GuardedBy("mServiceLock")
     @Nullable private IVirtualCameraService mVirtualCameraService;
 
     @GuardedBy("mCameras")
-    private final Set<VirtualCameraConfig> mCameras = new ArraySet<>();
+    private final Map<IBinder, CameraDescriptor> mCameras = new ArrayMap<>();
 
     public VirtualCameraController() {
         connectVirtualCameraService();
@@ -71,8 +74,12 @@
 
         try {
             if (registerCameraWithService(cameraConfig)) {
+                CameraDescriptor cameraDescriptor =
+                        new CameraDescriptor(cameraConfig);
+                IBinder binder = cameraConfig.getCallback().asBinder();
+                binder.linkToDeath(cameraDescriptor, 0 /* flags */);
                 synchronized (mCameras) {
-                    mCameras.add(cameraConfig);
+                    mCameras.put(binder, cameraDescriptor);
                 }
             } else {
                 // TODO(b/310857519): Revisit this to find a better way of indicating failure.
@@ -89,17 +96,22 @@
      * @param cameraConfig The {@link VirtualCameraConfig} sent by the client.
      */
     public void unregisterCamera(@NonNull VirtualCameraConfig cameraConfig) {
-        try {
-            if (mVirtualCameraService == null) {
-                Slog.w(TAG, "Virtual camera service is not connected.");
+        synchronized (mCameras) {
+            IBinder binder = cameraConfig.getCallback().asBinder();
+            if (!mCameras.containsKey(binder)) {
+                Slog.w(TAG, "Virtual camera was not registered.");
             } else {
-                mVirtualCameraService.unregisterCamera(cameraConfig.getCallback().asBinder());
+                connectVirtualCameraServiceIfNeeded();
+
+                try {
+                    synchronized (mServiceLock) {
+                        mVirtualCameraService.unregisterCamera(binder);
+                    }
+                    mCameras.remove(binder);
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
             }
-            synchronized (mCameras) {
-                mCameras.remove(cameraConfig);
-            }
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
         }
     }
 
@@ -108,7 +120,9 @@
         connectVirtualCameraServiceIfNeeded();
 
         try {
-            return mVirtualCameraService.getCameraId(cameraConfig.getCallback().asBinder());
+            synchronized (mServiceLock) {
+                return mVirtualCameraService.getCameraId(cameraConfig.getCallback().asBinder());
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -117,7 +131,9 @@
     @Override
     public void binderDied() {
         Slog.d(TAG, "Virtual camera service died.");
-        mVirtualCameraService = null;
+        synchronized (mServiceLock) {
+            mVirtualCameraService = null;
+        }
         synchronized (mCameras) {
             mCameras.clear();
         }
@@ -126,44 +142,49 @@
     /** Release resources associated with this controller. */
     public void close() {
         synchronized (mCameras) {
-            if (mVirtualCameraService == null) {
-                Slog.w(TAG, "Virtual camera service is not connected.");
-            } else {
-                for (VirtualCameraConfig config : mCameras) {
-                    try {
-                        mVirtualCameraService.unregisterCamera(config.getCallback().asBinder());
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "close(): Camera failed to be removed on camera "
-                                + "service.", e);
+            if (!mCameras.isEmpty()) {
+                connectVirtualCameraServiceIfNeeded();
+
+                synchronized (mServiceLock) {
+                    for (IBinder binder : mCameras.keySet()) {
+                        try {
+                            mVirtualCameraService.unregisterCamera(binder);
+                        } catch (RemoteException e) {
+                            Slog.w(TAG, "close(): Camera failed to be removed on camera "
+                                    + "service.", e);
+                        }
                     }
                 }
+                mCameras.clear();
             }
-            mCameras.clear();
         }
-        mVirtualCameraService = null;
+        synchronized (mServiceLock) {
+            mVirtualCameraService = null;
+        }
     }
 
     /** Dumps information about this {@link VirtualCameraController} for debugging purposes. */
     public void dump(PrintWriter fout, String indent) {
         fout.println(indent + "VirtualCameraController:");
         indent += indent;
-        fout.printf("%sService:%s\n", indent, mVirtualCameraService);
         synchronized (mCameras) {
             fout.printf("%sRegistered cameras:%d%n\n", indent, mCameras.size());
-            for (VirtualCameraConfig config : mCameras) {
-                fout.printf("%s token: %s\n", indent, config);
+            for (CameraDescriptor descriptor : mCameras.values()) {
+                fout.printf("%s token: %s\n", indent, descriptor.mConfig);
             }
         }
     }
 
     private void connectVirtualCameraServiceIfNeeded() {
-        // Try to connect to service if not connected already.
-        if (mVirtualCameraService == null) {
-            connectVirtualCameraService();
-        }
-        // Throw exception if we are unable to connect to service.
-        if (mVirtualCameraService == null) {
-            throw new IllegalStateException("Virtual camera service is not connected.");
+        synchronized (mServiceLock) {
+            // Try to connect to service if not connected already.
+            if (mVirtualCameraService == null) {
+                connectVirtualCameraService();
+            }
+            // Throw exception if we are unable to connect to service.
+            if (mVirtualCameraService == null) {
+                throw new IllegalStateException("Virtual camera service is not connected.");
+            }
         }
     }
 
@@ -188,7 +209,24 @@
 
     private boolean registerCameraWithService(VirtualCameraConfig config) throws RemoteException {
         VirtualCameraConfiguration serviceConfiguration = getServiceCameraConfiguration(config);
-        return mVirtualCameraService.registerCamera(config.getCallback().asBinder(),
-                serviceConfiguration);
+        synchronized (mServiceLock) {
+            return mVirtualCameraService.registerCamera(config.getCallback().asBinder(),
+                    serviceConfiguration);
+        }
+    }
+
+    private final class CameraDescriptor implements IBinder.DeathRecipient {
+
+        private final VirtualCameraConfig mConfig;
+
+        CameraDescriptor(VirtualCameraConfig config) {
+            mConfig = config;
+        }
+
+        @Override
+        public void binderDied() {
+            Slog.d(TAG, "Virtual camera binder died");
+            unregisterCamera(mConfig);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 7fe0682..c258370 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -1,5 +1,5 @@
-# BootReceiver
-per-file BootReceiver.java = gaillard@google.com
+# BootReceiver / Watchdog
+per-file BootReceiver.java,Watchdog.java = gaillard@google.com
 
 # Connectivity / Networking
 per-file ConnectivityService.java,ConnectivityServiceInitializer.java,NetworkManagementService.java,NsdService.java,VpnManagerService.java = file:/services/core/java/com/android/server/net/OWNERS
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 54c8ed3..6761073 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14150,7 +14150,8 @@
                                 || action.startsWith("android.intent.action.PACKAGE_")
                                 || action.startsWith("android.intent.action.UID_")
                                 || action.startsWith("android.intent.action.EXTERNAL_")
-                                || action.startsWith("android.bluetooth.")) {
+                                || action.startsWith("android.bluetooth.")
+                                || action.equals(Intent.ACTION_SHUTDOWN)) {
                             if (DEBUG_BROADCAST) {
                                 Slog.wtf(TAG,
                                         "System internals registering for " + filter.toLongString()
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index e656030..1928780 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -3013,7 +3013,7 @@
                                         mBatteryStatsConfig, Clock.SYSTEM_CLOCK, mMonotonicClock,
                                         null, mStats.mHandler, null, null,
                                         mUserManagerUserInfoProvider, mPowerProfile,
-                                        mCpuScalingPolicies, null);
+                                        mCpuScalingPolicies, new PowerStatsUidResolver());
                                 checkinStats.readSummaryFromParcel(in);
                                 in.recycle();
                                 checkinStats.dumpProtoLocked(mContext, fd, apps, flags,
@@ -3055,7 +3055,7 @@
                                         mBatteryStatsConfig, Clock.SYSTEM_CLOCK, mMonotonicClock,
                                         null, mStats.mHandler, null, null,
                                         mUserManagerUserInfoProvider, mPowerProfile,
-                                        mCpuScalingPolicies, null);
+                                        mCpuScalingPolicies, new PowerStatsUidResolver());
                                 checkinStats.readSummaryFromParcel(in);
                                 in.recycle();
                                 checkinStats.dumpCheckin(mContext, pw, apps, flags,
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index debf828..d848f4b 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -121,6 +121,7 @@
 
         // Display independent, mode dependent values
         float[] brightnessLevelsNits;
+        float[] brightnessLevels = null;
         float[] luxLevels;
         if (isForIdleMode) {
             brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
@@ -130,11 +131,21 @@
         } else {
             brightnessLevelsNits = displayDeviceConfig.getAutoBrightnessBrighteningLevelsNits();
             luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux();
+
+            brightnessLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevels();
+            if (brightnessLevels == null || brightnessLevels.length == 0) {
+                // Load the old configuration in the range [0, 255]. The values need to be
+                // normalized to the range [0, 1].
+                int[] brightnessLevelsInt = resources.getIntArray(
+                        com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
+                brightnessLevels = new float[brightnessLevelsInt.length];
+                for (int i = 0; i < brightnessLevels.length; i++) {
+                    brightnessLevels[i] = normalizeAbsoluteBrightness(brightnessLevelsInt[i]);
+                }
+            }
         }
 
         // Display independent, mode independent values
-        int[] brightnessLevelsBacklight = resources.getIntArray(
-                com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
         float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
                 com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
                 1, 1);
@@ -155,8 +166,8 @@
             builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
             return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange,
                     autoBrightnessAdjustmentMaxGamma, isForIdleMode, displayWhiteBalanceController);
-        } else if (isValidMapping(luxLevels, brightnessLevelsBacklight) && !isForIdleMode) {
-            return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
+        } else if (isValidMapping(luxLevels, brightnessLevels)) {
+            return new SimpleMappingStrategy(luxLevels, brightnessLevels,
                     autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout);
         } else {
             return null;
@@ -620,7 +631,7 @@
         private float mUserBrightness;
         private long mShortTermModelTimeout;
 
-        private SimpleMappingStrategy(float[] lux, int[] brightness, float maxGamma,
+        private SimpleMappingStrategy(float[] lux, float[] brightness, float maxGamma,
                 long timeout) {
             Preconditions.checkArgument(lux.length != 0 && brightness.length != 0,
                     "Lux and brightness arrays must not be empty!");
@@ -635,7 +646,7 @@
             mBrightness = new float[N];
             for (int i = 0; i < N; i++) {
                 mLux[i] = lux[i];
-                mBrightness[i] = normalizeAbsoluteBrightness(brightness[i]);
+                mBrightness[i] = brightness[i];
             }
 
             mMaxGamma = maxGamma;
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 70d4ad2..c26118e 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -20,6 +20,8 @@
 import android.os.Handler;
 import android.view.Display;
 
+import com.android.server.display.feature.DisplayManagerFlags;
+
 import java.io.PrintWriter;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -39,6 +41,7 @@
     private final Handler mHandler;
     private final Listener mListener;
     private final String mName;
+    private final DisplayManagerFlags mFeatureFlags;
 
     public static final int DISPLAY_DEVICE_EVENT_ADDED = 1;
     public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2;
@@ -50,13 +53,14 @@
     private static final AtomicInteger NEXT_DISPLAY_MODE_ID = new AtomicInteger(1);  // 0 = no mode.
 
     // Called with SyncRoot lock held.
-    public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
-            Context context, Handler handler, Listener listener, String name) {
+    DisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler,
+            Listener listener, String name, DisplayManagerFlags featureFlags) {
         mSyncRoot = syncRoot;
         mContext = context;
         mHandler = handler;
         mListener = listener;
         mName = name;
+        mFeatureFlags = featureFlags;
     }
 
     /**
@@ -88,6 +92,10 @@
         return mName;
     }
 
+    public final DisplayManagerFlags getFeatureFlags() {
+        return mFeatureFlags;
+    }
+
     /**
      * Registers the display adapter with the display manager.
      *
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 2fdf90d..3b05b47 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -400,6 +400,7 @@
     }
 
     private DisplayDeviceConfig loadDisplayDeviceConfig() {
-        return DisplayDeviceConfig.create(mContext, false);
+        return DisplayDeviceConfig.create(mContext, /* useConfigXml= */ false,
+                mDisplayAdapter.getFeatureFlags());
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index e6aa825..d97127c 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -57,6 +57,7 @@
 import com.android.server.display.config.HighBrightnessMode;
 import com.android.server.display.config.IntegerArray;
 import com.android.server.display.config.LuxThrottling;
+import com.android.server.display.config.LuxToBrightnessMapping;
 import com.android.server.display.config.NitsMap;
 import com.android.server.display.config.NonNegativeFloatToFloatPoint;
 import com.android.server.display.config.Point;
@@ -77,6 +78,7 @@
 import com.android.server.display.config.ThresholdPoint;
 import com.android.server.display.config.UsiVersion;
 import com.android.server.display.config.XmlParser;
+import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.utils.DebugUtils;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -310,16 +312,18 @@
  *          <darkeningLightDebounceIdleMillis>
  *              1000
  *          </darkeningLightDebounceIdleMillis>
- *          <displayBrightnessMapping>
- *              <displayBrightnessPoint>
- *                  <lux>50</lux>
- *                  <nits>45.32</nits>
- *              </displayBrightnessPoint>
- *              <displayBrightnessPoint>
- *                  <lux>80</lux>
- *                  <nits>75.43</nits>
- *              </displayBrightnessPoint>
- *          </displayBrightnessMapping>
+ *          <luxToBrightnessMapping>
+ *            <map>
+ *              <point>
+ *                <first>0</first>
+ *                <second>0.2</second>
+ *              </point>
+ *              <point>
+ *                <first>80</first>
+ *                <second>0.3</second>
+ *              </point>
+ *            </map>
+ *          </luxToBrightnessMapping>
  *      </autoBrightness>
  *
  *      <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease>
@@ -630,7 +634,6 @@
     // for the corresponding values above
     private float[] mBrightness;
 
-
     /**
      * Array of desired screen brightness in nits corresponding to the lux values
      * in the mBrightnessLevelsLux array. The display brightness is defined as the
@@ -640,20 +643,25 @@
     private float[] mBrightnessLevelsNits;
 
     /**
-     * Array of light sensor lux values to define our levels for auto backlight
-     * brightness support.
+     * Array of desired screen brightness corresponding to the lux values
+     * in the mBrightnessLevelsLux array. The brightness values must be non-negative and
+     * non-decreasing. They must be between {@link PowerManager.BRIGHTNESS_MIN} and
+     * {@link PowerManager.BRIGHTNESS_MAX}. This must be overridden in platform specific overlays
+     */
+    private float[] mBrightnessLevels;
+
+    /**
+     * Array of light sensor lux values to define our levels for auto-brightness support.
      *
-     * The N + 1 entries of this array define N control points defined in mBrightnessLevelsNits,
-     * with first value always being 0 lux
+     * The first lux value is always 0.
      *
-     * The control points must be strictly increasing.  Each control point
-     * corresponds to an entry in the brightness backlight values arrays.
-     * For example, if lux == level[1] (second element of the levels array)
-     * then the brightness will be determined by value[0] (first element
-     * of the brightness values array).
+     * The control points must be strictly increasing. Each control point corresponds to an entry
+     * in the brightness values arrays. For example, if lux == luxLevels[1] (second element
+     * of the levels array) then the brightness will be determined by brightnessLevels[1] (second
+     * element of the brightness values array).
      *
-     * Spline interpolation is used to determine the auto-brightness
-     * backlight values for lux levels between these control points.
+     * Spline interpolation is used to determine the auto-brightness values for lux levels between
+     * these control points.
      */
     private float[] mBrightnessLevelsLux;
 
@@ -849,9 +857,12 @@
      */
     private float mBrightnessCapForWearBedtimeMode;
 
+    private final DisplayManagerFlags mFlags;
+
     @VisibleForTesting
-    DisplayDeviceConfig(Context context) {
+    DisplayDeviceConfig(Context context, DisplayManagerFlags flags) {
         mContext = context;
+        mFlags = flags;
     }
 
     /**
@@ -867,9 +878,9 @@
      * @return A configuration instance for the specified display.
      */
     public static DisplayDeviceConfig create(Context context, long physicalDisplayId,
-            boolean isFirstDisplay) {
+            boolean isFirstDisplay, DisplayManagerFlags flags) {
         final DisplayDeviceConfig config = createWithoutDefaultValues(context, physicalDisplayId,
-                isFirstDisplay);
+                isFirstDisplay, flags);
 
         config.copyUninitializedValuesFromSecondaryConfig(loadDefaultConfigurationXml(context));
         return config;
@@ -884,28 +895,29 @@
      *                     or the default values.
      * @return A configuration instance.
      */
-    public static DisplayDeviceConfig create(Context context, boolean useConfigXml) {
+    public static DisplayDeviceConfig create(Context context, boolean useConfigXml,
+            DisplayManagerFlags flags) {
         final DisplayDeviceConfig config;
         if (useConfigXml) {
-            config = getConfigFromGlobalXml(context);
+            config = getConfigFromGlobalXml(context, flags);
         } else {
-            config = getConfigFromPmValues(context);
+            config = getConfigFromPmValues(context, flags);
         }
         return config;
     }
 
     private static DisplayDeviceConfig createWithoutDefaultValues(Context context,
-            long physicalDisplayId, boolean isFirstDisplay) {
+            long physicalDisplayId, boolean isFirstDisplay, DisplayManagerFlags flags) {
         DisplayDeviceConfig config;
 
         config = loadConfigFromDirectory(context, Environment.getProductDirectory(),
-                physicalDisplayId);
+                physicalDisplayId, flags);
         if (config != null) {
             return config;
         }
 
         config = loadConfigFromDirectory(context, Environment.getVendorDirectory(),
-                physicalDisplayId);
+                physicalDisplayId, flags);
         if (config != null) {
             return config;
         }
@@ -913,7 +925,7 @@
         // If no config can be loaded from any ddc xml at all,
         // prepare a whole config using the global config.xml.
         // Guaranteed not null
-        return create(context, isFirstDisplay);
+        return create(context, isFirstDisplay, flags);
     }
 
     private static DisplayConfiguration loadDefaultConfigurationXml(Context context) {
@@ -966,18 +978,19 @@
     }
 
     private static DisplayDeviceConfig loadConfigFromDirectory(Context context,
-            File baseDirectory, long physicalDisplayId) {
+            File baseDirectory, long physicalDisplayId, DisplayManagerFlags flags) {
         DisplayDeviceConfig config;
         // Create config using filename from physical ID (including "stable" bit).
         config = getConfigFromSuffix(context, baseDirectory, STABLE_ID_SUFFIX_FORMAT,
-                physicalDisplayId);
+                physicalDisplayId, flags);
         if (config != null) {
             return config;
         }
 
         // Create config using filename from physical ID (excluding "stable" bit).
         final long withoutStableFlag = physicalDisplayId & ~STABLE_FLAG;
-        config = getConfigFromSuffix(context, baseDirectory, NO_SUFFIX_FORMAT, withoutStableFlag);
+        config = getConfigFromSuffix(context, baseDirectory, NO_SUFFIX_FORMAT, withoutStableFlag,
+                flags);
         if (config != null) {
             return config;
         }
@@ -986,7 +999,7 @@
         final DisplayAddress.Physical physicalAddress =
                 DisplayAddress.fromPhysicalDisplayId(physicalDisplayId);
         int port = physicalAddress.getPort();
-        config = getConfigFromSuffix(context, baseDirectory, PORT_SUFFIX_FORMAT, port);
+        config = getConfigFromSuffix(context, baseDirectory, PORT_SUFFIX_FORMAT, port, flags);
         return config;
     }
 
@@ -1605,6 +1618,13 @@
     }
 
     /**
+     * @return Auto brightness brightening levels
+     */
+    public float[] getAutoBrightnessBrighteningLevels() {
+        return mBrightnessLevels;
+    }
+
+    /**
      * @return Default peak refresh rate of the associated display
      */
     public int getDefaultPeakRefreshRate() {
@@ -1857,6 +1877,7 @@
                 + mAutoBrightnessDarkeningLightDebounceIdle
                 + ", mBrightnessLevelsLux= " + Arrays.toString(mBrightnessLevelsLux)
                 + ", mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits)
+                + ", mBrightnessLevels= " + Arrays.toString(mBrightnessLevels)
                 + ", mDdcAutoBrightnessAvailable= " + mDdcAutoBrightnessAvailable
                 + ", mAutoBrightnessAvailable= " + mAutoBrightnessAvailable
                 + "\n"
@@ -1890,27 +1911,29 @@
     }
 
     private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory,
-            String suffixFormat, long idNumber) {
+            String suffixFormat, long idNumber, DisplayManagerFlags flags) {
 
         final String suffix = String.format(Locale.ROOT, suffixFormat, idNumber);
         final String filename = String.format(Locale.ROOT, CONFIG_FILE_FORMAT, suffix);
         final File filePath = Environment.buildPath(
                 baseDirectory, ETC_DIR, DISPLAY_CONFIG_DIR, filename);
-        final DisplayDeviceConfig config = new DisplayDeviceConfig(context);
+        final DisplayDeviceConfig config = new DisplayDeviceConfig(context, flags);
         if (config.initFromFile(filePath)) {
             return config;
         }
         return null;
     }
 
-    private static DisplayDeviceConfig getConfigFromGlobalXml(Context context) {
-        DisplayDeviceConfig config = new DisplayDeviceConfig(context);
+    private static DisplayDeviceConfig getConfigFromGlobalXml(Context context,
+            DisplayManagerFlags flags) {
+        DisplayDeviceConfig config = new DisplayDeviceConfig(context, flags);
         config.initFromGlobalXml();
         return config;
     }
 
-    private static DisplayDeviceConfig getConfigFromPmValues(Context context) {
-        DisplayDeviceConfig config = new DisplayDeviceConfig(context);
+    private static DisplayDeviceConfig getConfigFromPmValues(Context context,
+            DisplayManagerFlags flags) {
+        DisplayDeviceConfig config = new DisplayDeviceConfig(context, flags);
         config.initFromDefaultValues();
         return config;
     }
@@ -2615,8 +2638,23 @@
      * loading the value from the display config, and if not present, falls back to config.xml.
      */
     private void loadAutoBrightnessDisplayBrightnessMapping(AutoBrightness autoBrightnessConfig) {
-        if (autoBrightnessConfig == null
-                || autoBrightnessConfig.getDisplayBrightnessMapping() == null) {
+        if (mFlags.areAutoBrightnessModesEnabled() && autoBrightnessConfig != null
+                && autoBrightnessConfig.getLuxToBrightnessMapping() != null) {
+            LuxToBrightnessMapping mapping = autoBrightnessConfig.getLuxToBrightnessMapping();
+            final int size = mapping.getMap().getPoint().size();
+            mBrightnessLevels = new float[size];
+            mBrightnessLevelsLux = new float[size];
+            for (int i = 0; i < size; i++) {
+                float backlight = mapping.getMap().getPoint().get(i).getSecond().floatValue();
+                mBrightnessLevels[i] = mBacklightToBrightnessSpline.interpolate(backlight);
+                mBrightnessLevelsLux[i] = mapping.getMap().getPoint().get(i).getFirst()
+                        .floatValue();
+            }
+            if (size > 0 && mBrightnessLevelsLux[0] != 0) {
+                throw new IllegalArgumentException(
+                        "The first lux value in the display brightness mapping must be 0");
+            }
+        } else {
             mBrightnessLevelsNits = getFloatArray(mContext.getResources()
                     .obtainTypedArray(com.android.internal.R.array
                             .config_autoBrightnessDisplayValuesNits), PowerManager
@@ -2624,18 +2662,6 @@
             mBrightnessLevelsLux = getLuxLevels(mContext.getResources()
                     .getIntArray(com.android.internal.R.array
                             .config_autoBrightnessLevels));
-        } else {
-            final int size = autoBrightnessConfig.getDisplayBrightnessMapping()
-                    .getDisplayBrightnessPoint().size();
-            mBrightnessLevelsNits = new float[size];
-            // The first control point is implicit and always at 0 lux.
-            mBrightnessLevelsLux = new float[size + 1];
-            for (int i = 0; i < size; i++) {
-                mBrightnessLevelsNits[i] = autoBrightnessConfig.getDisplayBrightnessMapping()
-                        .getDisplayBrightnessPoint().get(i).getNits().floatValue();
-                mBrightnessLevelsLux[i + 1] = autoBrightnessConfig.getDisplayBrightnessMapping()
-                        .getDisplayBrightnessPoint().get(i).getLux().floatValue();
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6a7c17d..2ab15e6 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1853,7 +1853,7 @@
             // early apps like SetupWizard/Launcher. In particular, SUW is displayed using
             // the virtual display inside VR before any VR-specific apps even run.
             mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,
-                    mHandler, mDisplayDeviceRepo);
+                    mHandler, mDisplayDeviceRepo, mFlags);
             if (mVirtualDisplayAdapter != null) {
                 registerDisplayAdapterLocked(mVirtualDisplayAdapter);
             }
@@ -1871,7 +1871,7 @@
 
     private void registerOverlayDisplayAdapterLocked() {
         registerDisplayAdapterLocked(new OverlayDisplayAdapter(
-                mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler));
+                mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler, mFlags));
     }
 
     private void registerWifiDisplayAdapterLocked() {
@@ -1880,7 +1880,7 @@
                 || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
             mWifiDisplayAdapter = new WifiDisplayAdapter(
                     mSyncRoot, mContext, mHandler, mDisplayDeviceRepo,
-                    mPersistentDataStore);
+                    mPersistentDataStore, mFlags);
             registerDisplayAdapterLocked(mWifiDisplayAdapter);
         }
     }
@@ -3288,8 +3288,10 @@
     @VisibleForTesting
     static class Injector {
         VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
-                Handler handler, DisplayAdapter.Listener displayAdapterListener) {
-            return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener);
+                Handler handler, DisplayAdapter.Listener displayAdapterListener,
+                DisplayManagerFlags flags) {
+            return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
+                    flags);
         }
 
         LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index ff9a1ab..22898a6 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -84,8 +84,6 @@
 
     private final boolean mIsBootDisplayModeSupported;
 
-    private final DisplayManagerFlags mFlags;
-
     private final DisplayNotificationManager mDisplayNotificationManager;
 
     private Context mOverlayContext;
@@ -103,12 +101,11 @@
             Listener listener, DisplayManagerFlags flags,
             DisplayNotificationManager displayNotificationManager,
             Injector injector) {
-        super(syncRoot, context, handler, listener, TAG);
+        super(syncRoot, context, handler, listener, TAG, flags);
         mDisplayNotificationManager = displayNotificationManager;
         mInjector = injector;
         mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
         mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
-        mFlags = flags;
     }
 
     @Override
@@ -510,7 +507,7 @@
             // Load display device config
             final Context context = getOverlayContext();
             mDisplayDeviceConfig = mInjector.createDisplayDeviceConfig(context, mPhysicalDisplayId,
-                    mIsFirstDisplay);
+                    mIsFirstDisplay, getFeatureFlags());
 
             // Load brightness HWC quirk
             mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk(
@@ -831,7 +828,8 @@
                                     + ", state=" + Display.stateToString(state) + ")");
                         }
 
-                        boolean isDisplayOffloadEnabled = mFlags.isDisplayOffloadEnabled();
+                        boolean isDisplayOffloadEnabled =
+                                getFeatureFlags().isDisplayOffloadEnabled();
 
                         // We must tell sidekick/displayoffload to stop controlling the display
                         // before we can change its power mode, so do that first.
@@ -1377,8 +1375,8 @@
         }
 
         public DisplayDeviceConfig createDisplayDeviceConfig(Context context,
-                long physicalDisplayId, boolean isFirstDisplay) {
-            return DisplayDeviceConfig.create(context, physicalDisplayId, isFirstDisplay);
+                long physicalDisplayId, boolean isFirstDisplay, DisplayManagerFlags flags) {
+            return DisplayDeviceConfig.create(context, physicalDisplayId, isFirstDisplay, flags);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 2ce7690..22ff2d0 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.mode.DisplayModeDirector;
 
 import java.io.PrintWriter;
@@ -134,8 +135,9 @@
 
     // Called with SyncRoot lock held.
     public OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
-            Context context, Handler handler, Listener listener, Handler uiHandler) {
-        super(syncRoot, context, handler, listener, TAG);
+            Context context, Handler handler, Listener listener, Handler uiHandler,
+            DisplayManagerFlags featureFlags) {
+        super(syncRoot, context, handler, listener, TAG, featureFlags);
         mUiHandler = uiHandler;
     }
 
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index edbd424..ec5ad7d 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -61,6 +61,7 @@
 import android.view.SurfaceControl;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.feature.DisplayManagerFlags;
 
 import java.io.PrintWriter;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -88,7 +89,7 @@
 
     // Called with SyncRoot lock held.
     public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
-            Context context, Handler handler, Listener listener) {
+            Context context, Handler handler, Listener listener, DisplayManagerFlags featureFlags) {
         this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() {
             @Override
             public IBinder createDisplay(String name, boolean secure, float requestedRefreshRate) {
@@ -99,14 +100,15 @@
             public void destroyDisplay(IBinder displayToken) {
                 DisplayControl.destroyDisplay(displayToken);
             }
-        });
+        }, featureFlags);
     }
 
     @VisibleForTesting
     VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener,
-            SurfaceControlDisplayFactory surfaceControlDisplayFactory) {
-        super(syncRoot, context, handler, listener, TAG);
+            SurfaceControlDisplayFactory surfaceControlDisplayFactory,
+            DisplayManagerFlags featureFlags) {
+        super(syncRoot, context, handler, listener, TAG, featureFlags);
         mHandler = handler;
         mSurfaceControlDisplayFactory = surfaceControlDisplayFactory;
     }
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 7660cf8..aa98cd8 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -41,6 +41,7 @@
 
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.utils.DebugUtils;
 
 import java.io.PrintWriter;
@@ -99,8 +100,8 @@
     // Called with SyncRoot lock held.
     public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener,
-            PersistentDataStore persistentDataStore) {
-        super(syncRoot, context, handler, listener, TAG);
+            PersistentDataStore persistentDataStore, DisplayManagerFlags featureFlags) {
+        super(syncRoot, context, handler, listener, TAG, featureFlags);
 
         if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) {
             throw new RuntimeException("WiFi display was requested, "
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index eb87984..c71f0cf2 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -94,6 +94,10 @@
             Flags.FLAG_BRIGHTNESS_WEAR_BEDTIME_MODE_CLAMPER,
             Flags::brightnessWearBedtimeModeClamper);
 
+    private final FlagState mAutoBrightnessModesFlagState = new FlagState(
+            Flags.FLAG_AUTO_BRIGHTNESS_MODES,
+            Flags::autoBrightnessModes);
+
     /** Returns whether connected display management is enabled or not. */
     public boolean isConnectedDisplayManagementEnabled() {
         return mConnectedDisplayManagementFlagState.isEnabled();
@@ -187,6 +191,13 @@
     }
 
     /**
+     * @return Whether generic auto-brightness modes are enabled
+     */
+    public boolean areAutoBrightnessModesEnabled() {
+        return mAutoBrightnessModesFlagState.isEnabled();
+    }
+
+    /**
      * dumps all flagstates
      * @param pw printWriter
      */
@@ -206,6 +217,7 @@
         pw.println(" " + mBrightnessIntRangeUserPerceptionFlagState);
         pw.println(" " + mVsyncProximityVote);
         pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState);
+        pw.println(" " + mAutoBrightnessModesFlagState);
     }
 
     private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 9dab761..9dfa1ee 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -128,3 +128,11 @@
     bug: "293613040"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "auto_brightness_modes"
+    namespace: "display_manager"
+    description: "Feature flag for generic auto-brightness modes"
+    bug: "293613040"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 8eb03ec..8fa838d 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -21,8 +21,8 @@
 import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
 import static android.view.Display.Mode.INVALID_MODE_ID;
 
-import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRate;
 import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE;
+import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay;
 
 import android.annotation.IntegerRes;
 import android.annotation.NonNull;
@@ -925,16 +925,11 @@
     }
 
     @VisibleForTesting
-    DisplayObserver getDisplayObserver() {
-        return mDisplayObserver;
-    }
-
-    @VisibleForTesting
     DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
             float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
         synchronized (mLock) {
-            mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate,
-                    defaultRefreshRate, Display.DEFAULT_DISPLAY);
+            mSettingsObserver.updateRefreshRateSettingLocked(
+                    minRefreshRate, peakRefreshRate, defaultRefreshRate);
             return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY);
         }
     }
@@ -1268,23 +1263,9 @@
             mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
         }
 
-        /**
-         * Update refresh rate settings for all displays
-         */
         private void updateRefreshRateSettingLocked() {
-            Display[] displays = mInjector.getDisplays();
-            for (int i = 0; i < displays.length; i++) {
-                updateRefreshRateSettingLocked(displays[i].getDisplayId());
-            }
-        }
-
-        /**
-         * Update refresh rate settings for a specific display
-         * @param displayId The display ID
-         */
-        private void updateRefreshRateSettingLocked(int displayId) {
             final ContentResolver cr = mContext.getContentResolver();
-            float highestRefreshRate = findHighestRefreshRate(mContext, displayId);
+            float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext);
 
             float minRefreshRate = Settings.System.getFloatForUser(cr,
                     Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
@@ -1312,12 +1293,11 @@
                 }
             }
 
-            updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate,
-                    displayId);
+            updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
         }
 
-        private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
-                float defaultRefreshRate, int displayId) {
+        private void updateRefreshRateSettingLocked(
+                float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
             // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
             // used to predict if we're going to be doing frequent refresh rate switching, and if
             // so, enable the brightness observer. The logic here is more complicated and fragile
@@ -1325,9 +1305,9 @@
             Vote peakVote = peakRefreshRate == 0f
                     ? null
                     : Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate));
-            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
+            mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
                     peakVote);
-            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
+            mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
                     Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY));
             Vote defaultVote =
                     defaultRefreshRate == 0f
@@ -1484,8 +1464,7 @@
         }
     }
 
-    @VisibleForTesting
-    public final class DisplayObserver implements DisplayManager.DisplayListener {
+    private final class DisplayObserver implements DisplayManager.DisplayListener {
         // Note that we can never call into DisplayManager or any of the non-POD classes it
         // returns, while holding mLock since it may call into DMS, which might be simultaneously
         // calling into us already holding its own lock.
@@ -1577,7 +1556,6 @@
             updateDisplayModes(displayId, displayInfo);
             updateLayoutLimitedFrameRate(displayId, displayInfo);
             updateUserSettingDisplayPreferredSize(displayInfo);
-            mSettingsObserver.updateRefreshRateSettingLocked(displayId);
         }
 
         @Nullable
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 6f9b7d6..27b01a5 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -67,6 +67,7 @@
 import android.location.LocationManager;
 import android.location.LocationRequest;
 import android.location.LocationResult;
+import android.location.flags.Flags;
 import android.location.provider.ProviderProperties;
 import android.location.provider.ProviderRequest;
 import android.location.util.identity.CallerIdentity;
@@ -1048,10 +1049,22 @@
                 stopBatching();
 
                 if (mStarted && mGnssNative.getCapabilities().hasScheduling()) {
-                    // change period and/or lowPowerMode
-                    if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC,
-                            mFixInterval, mProviderRequest.isLowPower())) {
-                        Log.e(TAG, "set_position_mode failed in updateRequirements");
+                    if (Flags.gnssCallStopBeforeSetPositionMode()) {
+                        GnssPositionMode positionMode = new GnssPositionMode(mPositionMode,
+                                GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval,
+                                /* preferredAccuracy= */ 0,
+                                /* preferredTime= */ 0,
+                                mProviderRequest.isLowPower());
+                        if (!positionMode.equals(mLastPositionMode)) {
+                            stopNavigating();
+                            startNavigating();
+                        }
+                    } else {
+                        // change period and/or lowPowerMode
+                        if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC,
+                                mFixInterval, mProviderRequest.isLowPower())) {
+                            Log.e(TAG, "set_position_mode failed in updateRequirements");
+                        }
                     }
                 } else if (!mStarted) {
                     // start GPS
@@ -1234,11 +1247,32 @@
             }
 
             int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000;
-            if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC,
-                    interval, mProviderRequest.isLowPower())) {
-                setStarted(false);
-                Log.e(TAG, "set_position_mode failed in startNavigating()");
-                return;
+
+            if (Flags.gnssCallStopBeforeSetPositionMode()) {
+                boolean success = mGnssNative.setPositionMode(mPositionMode,
+                        GNSS_POSITION_RECURRENCE_PERIODIC, interval,
+                        /* preferredAccuracy= */ 0,
+                        /* preferredTime= */ 0,
+                        mProviderRequest.isLowPower());
+                if (success) {
+                    mLastPositionMode = new GnssPositionMode(mPositionMode,
+                            GNSS_POSITION_RECURRENCE_PERIODIC, interval,
+                            /* preferredAccuracy= */ 0,
+                            /* preferredTime= */ 0,
+                            mProviderRequest.isLowPower());
+                } else {
+                    mLastPositionMode = null;
+                    setStarted(false);
+                    Log.e(TAG, "set_position_mode failed in startNavigating()");
+                    return;
+                }
+            } else {
+                if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC,
+                        interval, mProviderRequest.isLowPower())) {
+                    setStarted(false);
+                    Log.e(TAG, "set_position_mode failed in startNavigating()");
+                    return;
+                }
             }
             if (!mGnssNative.start()) {
                 setStarted(false);
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 3b3d79e..07e0ddf 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -357,6 +357,12 @@
         final DeletePackageAction action;
         synchronized (mPm.mLock) {
             final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+            if (ps == null) {
+                if (DEBUG_REMOVE) {
+                    Slog.d(TAG, "Attempted to remove non-existent package " + packageName);
+                }
+                return false;
+            }
             final PackageSetting disabledPs = mPm.mSettings.getDisabledSystemPkgLPr(ps);
             if (PackageManagerServiceUtils.isSystemApp(ps)
                     && mPm.checkPermission(CONTROL_KEYGUARD, packageName, UserHandle.USER_SYSTEM)
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index b12da61..e9c4096 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -258,6 +258,11 @@
         }
 
         @Override // Binder call
+        public WebViewProviderInfo getDefaultWebViewPackage() {
+            return WebViewUpdateService.this.mImpl.getDefaultWebViewPackage();
+        }
+
+        @Override // Binder call
         public WebViewProviderInfo[] getAllWebViewPackages() {
             return WebViewUpdateService.this.mImpl.getWebViewPackages();
         }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 26c3fba..60dc4ff 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -421,6 +421,13 @@
         return providers;
     }
 
+    @Override
+    public WebViewProviderInfo getDefaultWebViewPackage() {
+        throw new IllegalStateException(
+                "getDefaultWebViewPackage shouldn't be called if update_service_v2 flag is"
+                        + " disabled.");
+    }
+
     private static class ProviderAndPackageInfo {
         public final WebViewProviderInfo provider;
         public final PackageInfo packageInfo;
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
index 89cb4c8..29782d9 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
@@ -24,6 +24,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.AndroidRuntimeException;
 import android.util.Slog;
 import android.webkit.UserPackage;
 import android.webkit.WebViewFactory;
@@ -374,6 +375,23 @@
         return providers;
     }
 
+    /**
+     * Returns the default WebView provider which should be first availableByDefault option in the
+     * system config.
+     */
+    @Override
+    public WebViewProviderInfo getDefaultWebViewPackage() {
+        WebViewProviderInfo[] webviewProviders = getWebViewPackages();
+        for (WebViewProviderInfo provider : webviewProviders) {
+            if (provider.availableByDefault) {
+                return provider;
+            }
+        }
+        // This should be unreachable because the config parser enforces that there is at least one
+        // availableByDefault provider.
+        throw new AndroidRuntimeException("No available by default WebView Provider.");
+    }
+
     private static class ProviderAndPackageInfo {
         public final WebViewProviderInfo provider;
         public final PackageInfo packageInfo;
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceInterface.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceInterface.java
index a9c3dc4..1772ef9 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceInterface.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceInterface.java
@@ -40,6 +40,8 @@
 
     WebViewProviderInfo[] getValidWebViewPackages();
 
+    WebViewProviderInfo getDefaultWebViewPackage();
+
     PackageInfo getCurrentWebViewPackage();
 
     boolean isMultiProcessEnabled();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d6302e0..bbaa691 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1582,6 +1582,7 @@
                 // An activity has changed order/visibility or the task is occluded by a transient
                 // activity, so this isn't just deliver-to-top
                 && mMovedToTopActivity == null
+                && !transitionController.hasOrderChanges()
                 && !transitionController.isTransientHide(startedActivityRootTask)) {
             // We just delivered to top, so there isn't an actual transition here.
             if (!forceTransientTransition) {
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index eafaf8c..6e7cf12 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -63,6 +63,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.UiThread;
 import com.android.server.am.PendingIntentRecord;
+import com.android.window.flags.Flags;
 
 import java.lang.annotation.Retention;
 import java.util.HashMap;
@@ -267,20 +268,25 @@
             mIntent = intent;
             mRealCallingPackage = mService.getPackageNameIfUnique(realCallingUid, realCallingPid);
             if (originatingPendingIntent == null) {
-                // grant creator BAL privileges unless explicitly opted out
+                // grant BAL privileges unless explicitly opted out
                 mBalAllowedByPiCreator =
                         checkedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
                                 == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED
                                 ? BackgroundStartPrivileges.NONE
                                 : BackgroundStartPrivileges.ALLOW_BAL;
+                mBalAllowedByPiSender =
+                        checkedOptions.getPendingIntentBackgroundActivityStartMode()
+                                == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED
+                                ? BackgroundStartPrivileges.NONE
+                                : BackgroundStartPrivileges.ALLOW_BAL;
             } else {
                 // for PendingIntents we restrict BAL based on target_sdk
                 mBalAllowedByPiCreator = getBackgroundStartPrivilegesAllowedByCreator(
                         callingUid, callingPackage, checkedOptions);
+                mBalAllowedByPiSender =
+                        PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller(
+                                checkedOptions, realCallingUid, mRealCallingPackage);
             }
-            mBalAllowedByPiSender =
-                    PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller(
-                            checkedOptions, realCallingUid, mRealCallingPackage);
             mAppSwitchState = mService.getBalAppSwitchesState();
             mCallingUidProcState = mService.mActiveUids.getUidState(callingUid);
             mIsCallingUidPersistentSystemProcess =
@@ -579,11 +585,12 @@
                     resultForCaller.allows() && resultForRealCaller.blocks());
         }
 
+        // Handle cases with explicit opt-in
         if (resultForCaller.allows()
                 && checkedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
                 == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) {
             if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "Activity start explicitly allowed by PI creator. "
+                Slog.d(TAG, "Activity start explicitly allowed by caller. "
                         + state.dump(resultForCaller, resultForRealCaller));
             }
             return statsLog(resultForCaller, state);
@@ -592,11 +599,12 @@
                 && checkedOptions.getPendingIntentBackgroundActivityStartMode()
                 == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) {
             if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "Activity start explicitly allowed by PI sender. "
+                Slog.d(TAG, "Activity start explicitly allowed by real caller. "
                         + state.dump(resultForCaller, resultForRealCaller));
             }
             return statsLog(resultForRealCaller, state);
         }
+        // Handle PendingIntent cases with default behavior next
         boolean callerCanAllow = resultForCaller.allows()
                 && checkedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
                 == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
@@ -807,13 +815,29 @@
                     "realCallingUid has BAL permission.");
         }
 
-        // don't abort if the realCallingUid has a visible window
-        // TODO(b/171459802): We should check appSwitchAllowed also
-        if (state.mRealCallingUidHasAnyVisibleWindow) {
-            return new BalVerdict(BAL_ALLOW_PENDING_INTENT,
-                    /*background*/ false,
-                    "realCallingUid has visible (non-toast) window.");
+        // Normal apps with visible app window will be allowed to start activity if app switching
+        // is allowed, or apps like live wallpaper with non app visible window will be allowed.
+        final boolean appSwitchAllowedOrFg = state.mAppSwitchState == APP_SWITCH_ALLOW
+                || state.mAppSwitchState == APP_SWITCH_FG_ONLY;
+        if (Flags.balImproveRealCallerVisibilityCheck()) {
+            if (appSwitchAllowedOrFg && state.mRealCallingUidHasAnyVisibleWindow) {
+                return new BalVerdict(BAL_ALLOW_PENDING_INTENT,
+                        /*background*/ false, "realCallingUid has visible window");
+            }
+            if (mService.mActiveUids.hasNonAppVisibleWindow(state.mRealCallingUid)) {
+                return new BalVerdict(BAL_ALLOW_PENDING_INTENT,
+                        /*background*/ false, "realCallingUid has non-app visible window");
+            }
+        } else {
+            // don't abort if the realCallingUid has a visible window
+            // TODO(b/171459802): We should check appSwitchAllowed also
+            if (state.mRealCallingUidHasAnyVisibleWindow) {
+                return new BalVerdict(BAL_ALLOW_PENDING_INTENT,
+                        /*background*/ false,
+                        "realCallingUid has visible (non-toast) window.");
+            }
         }
+
         // if the realCallingUid is a persistent system process, abort if the IntentSender
         // wasn't allowed to start an activity
         if (state.mForcedBalByPiSender.allowsBackgroundActivityStarts()
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 642d22f..e5604ec 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1756,6 +1756,27 @@
     }
 
     /**
+     * Checks if the transition contains order changes.
+     *
+     * This is a shallow check that doesn't account for collection in parallel, unlike
+     * {@code collectOrderChanges}
+     */
+    boolean hasOrderChanges() {
+        ArrayList<Task> onTopTasks = new ArrayList<>();
+        // Iterate over target displays to get up to date on top tasks.
+        // Cannot use `mOnTopTasksAtReady` as it's not populated before the `applyReady` is called.
+        for (DisplayContent dc : mTargetDisplays) {
+            addOnTopTasks(dc, onTopTasks);
+        }
+        for (Task task : onTopTasks) {
+            if (!mOnTopTasksStart.contains(task)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Collect tasks which moved-to-top as part of this transition. This also updates the
      * controller's latest-reported when relevant.
      *
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index bacfda5..e648d64 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -792,6 +792,12 @@
         mCollectingTransition.recordTaskOrder(wc);
     }
 
+    /** @see Transition#hasOrderChanges */
+    boolean hasOrderChanges() {
+        if (mCollectingTransition == null) return false;
+        return mCollectingTransition.hasOrderChanges();
+    }
+
     /**
      * Collects the window containers which need to be synced with the changing display area into
      * the current collecting transition.
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 8473532..c625b1e 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -592,42 +592,39 @@
                         minOccurs="0" maxOccurs="1">
                 <xs:annotation name="final"/>
             </xs:element>
-            <!-- Sets the brightness mapping of the desired screen brightness in nits to the
-             corresponding lux for the current display -->
-            <xs:element name="displayBrightnessMapping" type="displayBrightnessMapping"
+            <!-- Sets the brightness mapping of the desired screen brightness to the corresponding
+            lux for the current display -->
+            <xs:element name="luxToBrightnessMapping" type="luxToBrightnessMapping"
                         minOccurs="0" maxOccurs="1">
                 <xs:annotation name="final"/>
             </xs:element>
         </xs:sequence>
     </xs:complexType>
 
-    <!-- Represents the brightness mapping of the desired screen brightness in nits to the
-             corresponding lux for the current display -->
-    <xs:complexType name="displayBrightnessMapping">
-        <xs:sequence>
-            <!-- Sets the list of display brightness points, each representing the desired screen
-            brightness in nits to the corresponding lux for the current display
+    <!-- Sets the list of display brightness points, each representing the desired screen brightness
+    in a certain lux environment.
 
-            The N entries of this array define N + 1 control points as follows:
-            (1-based arrays)
+    The first value of each point is the lux value and the second value is the brightness value.
 
-            Point 1:            (0, nits[1]):             currentLux <= 0
-            Point 2:     (lux[1], nits[2]):       0 < currentLux <= lux[1]
-            Point 3:     (lux[2], nits[3]):  lux[2] < currentLux <= lux[3]
-            ...
-            Point N+1: (lux[N], nits[N+1]):            lux[N] < currentLux
+    The first lux value must be 0.
 
-            The control points must be strictly increasing. Each control point
-            corresponds to an entry in the brightness backlight values arrays.
-            For example, if currentLux == lux[1] (first element of the levels array)
-            then the brightness will be determined by nits[2] (second element
-            of the brightness values array).
-            -->
-            <xs:element name="displayBrightnessPoint" type="displayBrightnessPoint"
-                        minOccurs="1" maxOccurs="unbounded">
-                <xs:annotation name="final"/>
-            </xs:element>
-        </xs:sequence>
+    The control points must be strictly increasing.
+
+    Example: if currentLux == the second lux value in the mapping then the brightness will be
+    determined by the second brightness value in the mapping. Spline interpolation is used
+    to determine the auto-brightness values for lux levels between these control points.
+
+    The brightness values must be non-negative decimals within the range between the first and
+    the last brightness values in screenBrightnessMap.
+
+    This is used in place of config_autoBrightnessLevels and config_autoBrightnessLcdBacklightValues
+    defined in the config XML resource.
+    -->
+    <xs:complexType name="luxToBrightnessMapping">
+        <xs:element name="map" type="nonNegativeFloatToFloatMap">
+            <xs:annotation name="nonnull"/>
+            <xs:annotation name="final"/>
+        </xs:element>
     </xs:complexType>
 
     <!-- Represents a point in the display brightness mapping, representing the lux level from the
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 2437261..8c8c123 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -7,14 +7,14 @@
     method public final java.math.BigInteger getBrighteningLightDebounceMillis();
     method public final java.math.BigInteger getDarkeningLightDebounceIdleMillis();
     method public final java.math.BigInteger getDarkeningLightDebounceMillis();
-    method public final com.android.server.display.config.DisplayBrightnessMapping getDisplayBrightnessMapping();
     method public boolean getEnabled();
+    method public final com.android.server.display.config.LuxToBrightnessMapping getLuxToBrightnessMapping();
     method public final void setBrighteningLightDebounceIdleMillis(java.math.BigInteger);
     method public final void setBrighteningLightDebounceMillis(java.math.BigInteger);
     method public final void setDarkeningLightDebounceIdleMillis(java.math.BigInteger);
     method public final void setDarkeningLightDebounceMillis(java.math.BigInteger);
-    method public final void setDisplayBrightnessMapping(com.android.server.display.config.DisplayBrightnessMapping);
     method public void setEnabled(boolean);
+    method public final void setLuxToBrightnessMapping(com.android.server.display.config.LuxToBrightnessMapping);
   }
 
   public class BlockingZoneConfig {
@@ -78,11 +78,6 @@
     method public java.util.List<com.android.server.display.config.Density> getDensity();
   }
 
-  public class DisplayBrightnessMapping {
-    ctor public DisplayBrightnessMapping();
-    method public final java.util.List<com.android.server.display.config.DisplayBrightnessPoint> getDisplayBrightnessPoint();
-  }
-
   public class DisplayBrightnessPoint {
     ctor public DisplayBrightnessPoint();
     method public final java.math.BigInteger getLux();
@@ -222,6 +217,12 @@
     method @NonNull public final java.util.List<com.android.server.display.config.BrightnessLimitMap> getBrightnessLimitMap();
   }
 
+  public class LuxToBrightnessMapping {
+    ctor public LuxToBrightnessMapping();
+    method @NonNull public final com.android.server.display.config.NonNegativeFloatToFloatMap getMap();
+    method public final void setMap(@NonNull com.android.server.display.config.NonNegativeFloatToFloatMap);
+  }
+
   public class NitsMap {
     ctor public NitsMap();
     method public String getInterpolation();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index 97e5826..a2e80f0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -104,7 +104,7 @@
         468.5f,
     };
 
-    private static final int[] DISPLAY_LEVELS_BACKLIGHT = {
+    private static final int[] DISPLAY_LEVELS_INT = {
         9,
         30,
         45,
@@ -118,6 +118,20 @@
         255
     };
 
+    private static final float[] DISPLAY_LEVELS = {
+        0.03f,
+        0.11f,
+        0.17f,
+        0.24f,
+        0.3f,
+        0.37f,
+        0.46f,
+        0.57f,
+        0.7f,
+        0.87f,
+        1
+    };
+
     private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
     private static final float[] BACKLIGHT_RANGE_ZERO_TO_ONE = { 0.0f, 1.0f };
     private static final float[] DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT = { 0.03149606299f, 1.0f };
@@ -155,23 +169,23 @@
     DisplayWhiteBalanceController mMockDwbc;
 
     @Test
-    public void testSimpleStrategyMappingAtControlPoints() {
-        Resources res = createResources(DISPLAY_LEVELS_BACKLIGHT);
+    public void testSimpleStrategyMappingAtControlPoints_IntConfig() {
+        Resources res = createResources(DISPLAY_LEVELS_INT);
         DisplayDeviceConfig ddc = createDdc();
         BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNotNull("BrightnessMappingStrategy should not be null", simple);
         for (int i = 0; i < LUX_LEVELS.length; i++) {
             final float expectedLevel = MathUtils.map(PowerManager.BRIGHTNESS_OFF + 1,
                     PowerManager.BRIGHTNESS_ON, PowerManager.BRIGHTNESS_MIN,
-                    PowerManager.BRIGHTNESS_MAX, DISPLAY_LEVELS_BACKLIGHT[i]);
+                    PowerManager.BRIGHTNESS_MAX, DISPLAY_LEVELS_INT[i]);
             assertEquals(expectedLevel,
                     simple.getBrightness(LUX_LEVELS[i]), 0.0001f /*tolerance*/);
         }
     }
 
     @Test
-    public void testSimpleStrategyMappingBetweenControlPoints() {
-        Resources res = createResources(DISPLAY_LEVELS_BACKLIGHT);
+    public void testSimpleStrategyMappingBetweenControlPoints_IntConfig() {
+        Resources res = createResources(DISPLAY_LEVELS_INT);
         DisplayDeviceConfig ddc = createDdc();
         BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNotNull("BrightnessMappingStrategy should not be null", simple);
@@ -179,14 +193,42 @@
             final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
             final float backlight = simple.getBrightness(lux) * PowerManager.BRIGHTNESS_ON;
             assertTrue("Desired brightness should be between adjacent control points.",
-                    backlight > DISPLAY_LEVELS_BACKLIGHT[i - 1]
-                            && backlight < DISPLAY_LEVELS_BACKLIGHT[i]);
+                    backlight > DISPLAY_LEVELS_INT[i - 1]
+                            && backlight < DISPLAY_LEVELS_INT[i]);
+        }
+    }
+
+    @Test
+    public void testSimpleStrategyMappingAtControlPoints_FloatConfig() {
+        Resources res = createResources(EMPTY_INT_ARRAY);
+        DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY, EMPTY_FLOAT_ARRAY, LUX_LEVELS,
+                EMPTY_FLOAT_ARRAY, DISPLAY_LEVELS);
+        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+        assertNotNull("BrightnessMappingStrategy should not be null", simple);
+        for (int i = 0; i < LUX_LEVELS.length; i++) {
+            assertEquals(DISPLAY_LEVELS[i], simple.getBrightness(LUX_LEVELS[i]),
+                    /* tolerance= */ 0.0001f);
+        }
+    }
+
+    @Test
+    public void testSimpleStrategyMappingBetweenControlPoints_FloatConfig() {
+        Resources res = createResources(EMPTY_INT_ARRAY);
+        DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY, EMPTY_FLOAT_ARRAY, LUX_LEVELS,
+                EMPTY_FLOAT_ARRAY, DISPLAY_LEVELS);
+        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+        assertNotNull("BrightnessMappingStrategy should not be null", simple);
+        for (int i = 1; i < LUX_LEVELS.length; i++) {
+            final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
+            final float brightness = simple.getBrightness(lux);
+            assertTrue("Desired brightness should be between adjacent control points.",
+                    brightness > DISPLAY_LEVELS[i - 1] && brightness < DISPLAY_LEVELS[i]);
         }
     }
 
     @Test
     public void testSimpleStrategyIgnoresNewConfiguration() {
-        Resources res = createResources(DISPLAY_LEVELS_BACKLIGHT);
+        Resources res = createResources(DISPLAY_LEVELS_INT);
         DisplayDeviceConfig ddc = createDdc();
         BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
 
@@ -201,14 +243,14 @@
 
     @Test
     public void testSimpleStrategyIgnoresNullConfiguration() {
-        Resources res = createResources(DISPLAY_LEVELS_BACKLIGHT);
+        Resources res = createResources(DISPLAY_LEVELS_INT);
         DisplayDeviceConfig ddc = createDdc();
         BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
 
         strategy.setBrightnessConfiguration(null);
-        final int n = DISPLAY_LEVELS_BACKLIGHT.length;
+        final int n = DISPLAY_LEVELS_INT.length;
         final float expectedBrightness =
-                (float) DISPLAY_LEVELS_BACKLIGHT[n - 1] / PowerManager.BRIGHTNESS_ON;
+                (float) DISPLAY_LEVELS_INT[n - 1] / PowerManager.BRIGHTNESS_ON;
         assertEquals(expectedBrightness,
                 strategy.getBrightness(LUX_LEVELS[n - 1]), 0.0001f /*tolerance*/);
     }
@@ -322,7 +364,7 @@
 
     @Test
     public void testDefaultStrategyIsPhysical() {
-        Resources res = createResources(DISPLAY_LEVELS_BACKLIGHT);
+        Resources res = createResources(DISPLAY_LEVELS_INT);
         DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS,
                 DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, LUX_LEVELS, DISPLAY_LEVELS_NITS);
         BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
@@ -363,13 +405,13 @@
         BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
 
-        res = createResources(DISPLAY_LEVELS_BACKLIGHT);
+        res = createResources(DISPLAY_LEVELS_INT);
         strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
 
         // Extra backlight level
         final int[] backlight = Arrays.copyOf(
-                DISPLAY_LEVELS_BACKLIGHT, DISPLAY_LEVELS_BACKLIGHT.length + 1);
+                DISPLAY_LEVELS_INT, DISPLAY_LEVELS_INT.length + 1);
         backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
         res = createResources(backlight);
         ddc = createDdc(DISPLAY_RANGE_NITS,
@@ -410,7 +452,7 @@
                 LUX_LEVELS, DISPLAY_LEVELS_NITS);
         assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
         ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
-        res = createResources(DISPLAY_LEVELS_BACKLIGHT);
+        res = createResources(DISPLAY_LEVELS_INT);
         assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
     }
 
@@ -546,16 +588,24 @@
         when(mockDdc.getBrightness()).thenReturn(backlightArray);
         when(mockDdc.getAutoBrightnessBrighteningLevelsLux()).thenReturn(LUX_LEVELS);
         when(mockDdc.getAutoBrightnessBrighteningLevelsNits()).thenReturn(EMPTY_FLOAT_ARRAY);
+        when(mockDdc.getAutoBrightnessBrighteningLevels()).thenReturn(EMPTY_FLOAT_ARRAY);
         return mockDdc;
     }
 
     private DisplayDeviceConfig createDdc(float[] nitsArray, float[] backlightArray,
             float[] luxLevelsFloat, float[] brightnessLevelsNits) {
+        return createDdc(nitsArray, backlightArray, luxLevelsFloat, brightnessLevelsNits,
+                EMPTY_FLOAT_ARRAY);
+    }
+
+    private DisplayDeviceConfig createDdc(float[] nitsArray, float[] backlightArray,
+            float[] luxLevelsFloat, float[] brightnessLevelsNits, float[] brightnessLevels) {
         DisplayDeviceConfig mockDdc = mock(DisplayDeviceConfig.class);
         when(mockDdc.getNits()).thenReturn(nitsArray);
         when(mockDdc.getBrightness()).thenReturn(backlightArray);
         when(mockDdc.getAutoBrightnessBrighteningLevelsLux()).thenReturn(luxLevelsFloat);
         when(mockDdc.getAutoBrightnessBrighteningLevelsNits()).thenReturn(brightnessLevelsNits);
+        when(mockDdc.getAutoBrightnessBrighteningLevels()).thenReturn(brightnessLevels);
         return mockDdc;
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index e80e9e8..31d7e88 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -50,6 +50,7 @@
 import com.android.internal.display.BrightnessSynchronizer;
 import com.android.server.display.config.HdrBrightnessData;
 import com.android.server.display.config.ThermalStatus;
+import com.android.server.display.feature.DisplayManagerFlags;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -93,10 +94,14 @@
     @Mock
     private Resources mResources;
 
+    @Mock
+    private DisplayManagerFlags mFlags;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mContext.getResources()).thenReturn(mResources);
+        when(mFlags.areAutoBrightnessModesEnabled()).thenReturn(true);
         mockDeviceConfigs();
     }
 
@@ -111,10 +116,6 @@
         assertArrayEquals(mDisplayDeviceConfig.getBrightness(), BRIGHTNESS, ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getNits(), NITS, ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getBacklight(), BRIGHTNESS, ZERO_DELTA);
-        assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
-                float[]{0.0f, 50.0f, 80.0f}, ZERO_DELTA);
-        assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
-                float[]{45.32f, 75.43f}, ZERO_DELTA);
 
         // Test thresholds
         assertEquals(10, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(),
@@ -607,7 +608,7 @@
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
                 float[]{2.0f, 200.0f, 600.0f}, ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
-                float[]{0.0f, 0.0f, 110.0f, 500.0f}, ZERO_DELTA);
+                float[]{0.0f, 110.0f, 500.0f}, ZERO_DELTA);
 
         // Test thresholds
         assertEquals(0, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(), ZERO_DELTA);
@@ -727,6 +728,31 @@
         assertEquals(0.1f, mDisplayDeviceConfig.getBrightnessCapForWearBedtimeMode(), ZERO_DELTA);
     }
 
+    @Test
+    public void testAutoBrightnessBrighteningLevels() throws IOException {
+        setupDisplayDeviceConfigFromDisplayConfigFile(getContent(getValidLuxThrottling(),
+                getValidProxSensor(), /* includeIdleMode= */ false));
+
+        assertArrayEquals(new float[]{0.0f, 80},
+                mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0.2f, 0.3f},
+                mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(), SMALL_DELTA);
+    }
+
+    @Test
+    public void testAutoBrightnessBrighteningLevels_FeatureFlagOff() throws IOException {
+        when(mFlags.areAutoBrightnessModesEnabled()).thenReturn(false);
+        setupDisplayDeviceConfigFromConfigResourceFile();
+        setupDisplayDeviceConfigFromDisplayConfigFile(getContent(getValidLuxThrottling(),
+                getValidProxSensor(), /* includeIdleMode= */ false));
+
+        assertNull(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels());
+        assertArrayEquals(new float[]{0, 110, 500},
+                mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), ZERO_DELTA);
+        assertArrayEquals(new float[]{2, 200, 600},
+                mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), SMALL_DELTA);
+    }
+
     private String getValidLuxThrottling() {
         return "<luxThrottling>\n"
                 + "    <brightnessLimitMap>\n"
@@ -1048,8 +1074,8 @@
                 +   "<screenBrightnessRampDecreaseMaxIdleMillis>"
                 +       "5000"
                 +   "</screenBrightnessRampDecreaseMaxIdleMillis>\n";
-
     }
+
     private String getContent() {
         return getContent(getValidLuxThrottling(), getValidProxSensor(),
                 /* includeIdleMode= */ true);
@@ -1100,16 +1126,18 @@
                 +       "<brighteningLightDebounceMillis>2000</brighteningLightDebounceMillis>\n"
                 +       "<darkeningLightDebounceMillis>1000</darkeningLightDebounceMillis>\n"
                 + (includeIdleMode ? getRampSpeedsIdle() : "")
-                +       "<displayBrightnessMapping>\n"
-                +            "<displayBrightnessPoint>\n"
-                +                "<lux>50</lux>\n"
-                +                "<nits>45.32</nits>\n"
-                +            "</displayBrightnessPoint>\n"
-                +            "<displayBrightnessPoint>\n"
-                +                "<lux>80</lux>\n"
-                +                "<nits>75.43</nits>\n"
-                +            "</displayBrightnessPoint>\n"
-                +       "</displayBrightnessMapping>\n"
+                +       "<luxToBrightnessMapping>\n"
+                +           "<map>\n"
+                +               "<point>\n"
+                +                   "<first>0</first>\n"
+                +                   "<second>0.2</second>\n"
+                +               "</point>\n"
+                +               "<point>\n"
+                +                   "<first>80</first>\n"
+                +                   "<second>0.3</second>\n"
+                +               "</point>\n"
+                +           "</map>\n"
+                +       "</luxToBrightnessMapping>\n"
                 +   "</autoBrightness>\n"
                 +  getPowerThrottlingConfig()
                 +   "<highBrightnessMode enabled=\"true\">\n"
@@ -1386,7 +1414,7 @@
     private void setupDisplayDeviceConfigFromDisplayConfigFile(String content) throws IOException {
         Path tempFile = Files.createTempFile("display_config", ".tmp");
         Files.write(tempFile, content.getBytes(StandardCharsets.UTF_8));
-        mDisplayDeviceConfig = new DisplayDeviceConfig(mContext);
+        mDisplayDeviceConfig = new DisplayDeviceConfig(mContext, mFlags);
         mDisplayDeviceConfig.initFromFile(tempFile.toFile());
     }
 
@@ -1395,25 +1423,15 @@
         when(mResources.obtainTypedArray(
                 com.android.internal.R.array.config_screenBrightnessNits))
                 .thenReturn(screenBrightnessNits);
-        TypedArray screenBrightnessBacklight = createFloatTypedArray(new
-                float[]{0.0f, 120.0f, 255.0f});
-        when(mResources.obtainTypedArray(
-                com.android.internal.R.array.config_screenBrightnessBacklight))
-                .thenReturn(screenBrightnessBacklight);
         when(mResources.getIntArray(com.android.internal.R.array
                 .config_screenBrightnessBacklight)).thenReturn(new int[]{0, 120, 255});
 
-        when(mResources.getIntArray(com.android.internal.R.array
-                .config_autoBrightnessLevels)).thenReturn(new int[]{30, 80});
-        when(mResources.getIntArray(com.android.internal.R.array
-                .config_autoBrightnessDisplayValuesNits)).thenReturn(new int[]{25, 55});
-
         TypedArray screenBrightnessLevelNits = createFloatTypedArray(new
                 float[]{2.0f, 200.0f, 600.0f});
         when(mResources.obtainTypedArray(
                 com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
                 .thenReturn(screenBrightnessLevelNits);
-        int[] screenBrightnessLevelLux = new int[]{0, 110, 500};
+        int[] screenBrightnessLevelLux = new int[]{110, 500};
         when(mResources.getIntArray(
                 com.android.internal.R.array.config_autoBrightnessLevels))
                 .thenReturn(screenBrightnessLevelLux);
@@ -1475,7 +1493,8 @@
                 R.integer.config_screenBrightnessCapForWearBedtimeMode))
                 .thenReturn(35);
 
-        mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, true);
+        mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, /* useConfigXml= */ true,
+                mFlags);
     }
 
     private TypedArray createFloatTypedArray(float[] vals) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
index 4fd8f26..dc6abf1 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
@@ -57,6 +57,9 @@
     @Mock
     private SurfaceControl.Transaction mMockTransaction;
 
+    @Mock
+    private DisplayAdapter mMockDisplayAdapter;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -67,34 +70,39 @@
 
     @Test
     public void testGetDisplaySurfaceDefaultSizeLocked_notRotated() {
-        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+                mMockDisplayAdapter);
         assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
     }
 
     @Test
     public void testGetDisplaySurfaceDefaultSizeLocked_rotation0() {
-        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+                mMockDisplayAdapter);
         displayDevice.setProjectionLocked(mMockTransaction, ROTATION_0, new Rect(), new Rect());
         assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
     }
 
     @Test
     public void testGetDisplaySurfaceDefaultSizeLocked_rotation90() {
-        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+                mMockDisplayAdapter);
         displayDevice.setProjectionLocked(mMockTransaction, ROTATION_90, new Rect(), new Rect());
         assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
     }
 
     @Test
     public void testGetDisplaySurfaceDefaultSizeLocked_rotation180() {
-        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+                mMockDisplayAdapter);
         displayDevice.setProjectionLocked(mMockTransaction, ROTATION_180, new Rect(), new Rect());
         assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
     }
 
     @Test
     public void testGetDisplaySurfaceDefaultSizeLocked_rotation270() {
-        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+                mMockDisplayAdapter);
         displayDevice.setProjectionLocked(mMockTransaction, ROTATION_270, new Rect(), new Rect());
         assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
     }
@@ -102,8 +110,9 @@
     private static class FakeDisplayDevice extends DisplayDevice {
         private final DisplayDeviceInfo mDisplayDeviceInfo;
 
-        FakeDisplayDevice(DisplayDeviceInfo displayDeviceInfo) {
-            super(null, null, "", InstrumentationRegistry.getInstrumentation().getContext());
+        FakeDisplayDevice(DisplayDeviceInfo displayDeviceInfo, DisplayAdapter displayAdapter) {
+            super(displayAdapter, /* displayToken= */ null, /* uniqueId= */ "",
+                    InstrumentationRegistry.getInstrumentation().getContext());
             mDisplayDeviceInfo = displayDeviceInfo;
         }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 55f56e9..02e3ef4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -212,7 +212,8 @@
             new DisplayManagerService.Injector() {
                 @Override
                 VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
-                        Context context, Handler handler, DisplayAdapter.Listener listener) {
+                        Context context, Handler handler, DisplayAdapter.Listener listener,
+                        DisplayManagerFlags flags) {
                     return mMockVirtualDisplayAdapter;
                 }
 
@@ -251,7 +252,8 @@
 
         @Override
         VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
-                Handler handler, DisplayAdapter.Listener displayAdapterListener) {
+                Handler handler, DisplayAdapter.Listener displayAdapterListener,
+                DisplayManagerFlags flags) {
             return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
                     new VirtualDisplayAdapter.SurfaceControlDisplayFactory() {
                         @Override
@@ -263,7 +265,7 @@
                         @Override
                         public void destroyDisplay(IBinder displayToken) {
                         }
-                    });
+                    }, flags);
         }
 
         @Override
@@ -329,6 +331,7 @@
     @Mock SensorManager mSensorManager;
     @Mock DisplayDeviceConfig mMockDisplayDeviceConfig;
     @Mock PackageManagerInternal mMockPackageManagerInternal;
+    @Mock DisplayAdapter mMockDisplayAdapter;
 
     @Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
     @Mock DisplayManagerFlags mMockFlags;
@@ -788,7 +791,8 @@
                 new DisplayManagerService.Injector() {
                     @Override
                     VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
-                            Context context, Handler handler, DisplayAdapter.Listener listener) {
+                            Context context, Handler handler, DisplayAdapter.Listener listener,
+                            DisplayManagerFlags flags) {
                         return null;  // return null for the adapter.  This should cause a failure.
                     }
 
@@ -3194,7 +3198,7 @@
         private DisplayDeviceInfo mDisplayDeviceInfo;
 
         FakeDisplayDevice() {
-            super(null, null, "", mContext);
+            super(mMockDisplayAdapter, /* displayToken= */ null, /* uniqueId= */ "", mContext);
         }
 
         public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 8270845..f36854b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -1455,8 +1455,8 @@
         // mMockContext and values will be loaded from mMockResources.
         @Override
         public DisplayDeviceConfig createDisplayDeviceConfig(Context context,
-                long physicalDisplayId, boolean isFirstDisplay) {
-            return DisplayDeviceConfig.create(context, isFirstDisplay);
+                long physicalDisplayId, boolean isFirstDisplay, DisplayManagerFlags flags) {
+            return DisplayDeviceConfig.create(context, isFirstDisplay, flags);
         }
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 43d2b8f..28ec896 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -119,8 +119,8 @@
     @Mock IThermalService mIThermalServiceMock;
     @Spy DeviceStateToLayoutMap mDeviceStateToLayoutMapSpy =
             new DeviceStateToLayoutMap(mIdProducer, NON_EXISTING_FILE);
-    @Mock
-    DisplayManagerFlags mFlagsMock;
+    @Mock DisplayManagerFlags mFlagsMock;
+    @Mock DisplayAdapter mDisplayAdapterMock;
 
     @Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
     @Captor ArgumentCaptor<Integer> mDisplayEventCaptor;
@@ -1075,7 +1075,8 @@
         private int mState;
 
         TestDisplayDevice() {
-            super(null, null, "test_display_" + sUniqueTestDisplayId++, mContextMock);
+            super(mDisplayAdapterMock, /* displayToken= */ null,
+                    "test_display_" + sUniqueTestDisplayId++, mContextMock);
             mInfo = new DisplayDeviceInfo();
         }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
index 9f91916..5676a38 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -32,9 +32,12 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -51,8 +54,12 @@
     private TestInjector mInjector;
     private TestLooper mTestLooper;
 
+    @Mock
+    private DisplayAdapter mDisplayAdapter;
+
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mInjector = new TestInjector();
         mTestLooper = new TestLooper();
         Handler handler = new Handler(mTestLooper.getLooper());
@@ -62,8 +69,8 @@
     @Test
     public void testLoadBrightness() {
         final String uniqueDisplayId = "test:123";
-        final DisplayDevice testDisplayDevice = new DisplayDevice(
-                null, null, uniqueDisplayId, null) {
+        final DisplayDevice testDisplayDevice = new DisplayDevice(mDisplayAdapter,
+                /* displayToken= */ null, uniqueDisplayId, /* context= */ null) {
             @Override
             public boolean hasStableUniqueId() {
                 return true;
@@ -100,7 +107,8 @@
     public void testSetBrightness_brightnessTagWithNoUserId_updatesToBrightnessTagWithUserId() {
         final String uniqueDisplayId = "test:123";
         final DisplayDevice testDisplayDevice =
-                new DisplayDevice(null, null, uniqueDisplayId, null) {
+                new DisplayDevice(mDisplayAdapter, /* displayToken= */ null, uniqueDisplayId,
+                        /* context= */ null) {
             @Override
             public boolean hasStableUniqueId() {
                 return true;
@@ -273,7 +281,8 @@
         assertNull(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
                 userSerial));
 
-        DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
+        DisplayDevice testDisplayDevice = new DisplayDevice(mDisplayAdapter,
+                /* displayToken= */ null, uniqueDisplayId, /* context= */ null) {
             @Override
             public boolean hasStableUniqueId() {
                 return true;
@@ -319,7 +328,8 @@
         assertNull(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
                 userSerial));
 
-        DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
+        DisplayDevice testDisplayDevice = new DisplayDevice(mDisplayAdapter,
+                /* displayToken= */ null, uniqueDisplayId, /* context= */ null) {
             @Override
             public boolean hasStableUniqueId() {
                 return false;
@@ -386,7 +396,8 @@
     @Test
     public void testStoreAndRestoreResolution() {
         final String uniqueDisplayId = "test:123";
-        DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
+        DisplayDevice testDisplayDevice = new DisplayDevice(mDisplayAdapter,
+                /* displayToken= */ null, uniqueDisplayId, /* context= */ null) {
             @Override
             public boolean hasStableUniqueId() {
                 return true;
@@ -422,7 +433,8 @@
     @Test
     public void testStoreAndRestoreRefreshRate() {
         final String uniqueDisplayId = "test:123";
-        DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
+        DisplayDevice testDisplayDevice = new DisplayDevice(mDisplayAdapter,
+                /* displayToken= */ null, uniqueDisplayId, /* context= */ null) {
             @Override
             public boolean hasStableUniqueId() {
                 return true;
@@ -455,7 +467,8 @@
     @Test
     public void testBrightnessInitialisesWithInvalidFloat() {
         final String uniqueDisplayId = "test:123";
-        DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
+        DisplayDevice testDisplayDevice = new DisplayDevice(mDisplayAdapter,
+                /* displayToken= */ null, uniqueDisplayId, /* context= */ null) {
             @Override
             public boolean hasStableUniqueId() {
                 return true;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
index b7cbac5..5c50acb 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
@@ -72,27 +72,14 @@
 
     @Test
     public void testFindHighestRefreshRateForDefaultDisplay() {
-        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
-        assertEquals(120,
-                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
-                /* delta= */ 0);
-    }
-
-    @Test
-    public void testFindHighestRefreshRate() {
-        int displayId = 13;
-        when(mDisplayManagerMock.getDisplay(displayId)).thenReturn(mDisplayMock);
-        assertEquals(120,
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, displayId),
-                /* delta= */ 0);
-    }
-
-    @Test
-    public void testFindHighestRefreshRate_DisplayIsNull() {
         when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
         assertEquals(DEFAULT_REFRESH_RATE,
                 RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
                 /* delta= */ 0);
 
+        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+        assertEquals(120,
+                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+                /* delta= */ 0);
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index 73e7ba0..c01b15c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -28,6 +28,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.testutils.TestHandler;
 
 import org.junit.Before;
@@ -59,13 +60,17 @@
 
     private VirtualDisplayAdapter mVirtualDisplayAdapter;
 
+    @Mock
+    private DisplayManagerFlags mFeatureFlags;
+
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mHandler = new TestHandler(null);
         mVirtualDisplayAdapter = new VirtualDisplayAdapter(new DisplayManagerService.SyncRoot(),
-                mContextMock, mHandler, mMockListener, mMockSufaceControlDisplayFactory);
+                mContextMock, mHandler, mMockListener, mMockSufaceControlDisplayFactory,
+                mFeatureFlags);
 
         when(mMockCallback.asBinder()).thenReturn(mMockBinder);
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index d085923..60a0c03 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -290,7 +290,6 @@
     };
 
     private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY;
-    private static final int DISPLAY_ID_2 = Display.DEFAULT_DISPLAY + 1;
     private static final int MODE_ID = 1;
     private static final float TRANSITION_POINT = 0.763f;
 
@@ -1551,12 +1550,9 @@
     public void testPeakRefreshRate_FlagEnabled() {
         when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                 .thenReturn(true);
-        float highestRefreshRate1 = 130;
-        float highestRefreshRate2 = 132;
-        doReturn(highestRefreshRate1).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
-        doReturn(highestRefreshRate2).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID_2));
+        float highestRefreshRate = 130;
+        doReturn(highestRefreshRate).when(() ->
+                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
         DisplayModeDirector director =
                 createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
         director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -1567,14 +1563,10 @@
 
         setPeakRefreshRate(Float.POSITIVE_INFINITY);
 
-        Vote vote1 = director.getVote(DISPLAY_ID,
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
                 Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
-        Vote vote2 = director.getVote(DISPLAY_ID_2,
-                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
-        assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 0,
-                /* frameRateHigh= */ highestRefreshRate1);
-        assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 0,
-                /* frameRateHigh= */ highestRefreshRate2);
+        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+                highestRefreshRate);
     }
 
     @Test
@@ -1592,54 +1584,19 @@
 
         setPeakRefreshRate(peakRefreshRate);
 
-        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
-        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
-                /* frameRateHigh= */ peakRefreshRate);
-    }
-
-    @Test
-    public void testPeakRefreshRate_DisplayChanged() {
-        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
-                .thenReturn(true);
-        float highestRefreshRate = 130;
-        doReturn(highestRefreshRate).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
-        DisplayModeDirector director =
-                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
-        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
-
-        Sensor lightSensor = createLightSensor();
-        SensorManager sensorManager = createMockSensorManager(lightSensor);
-        director.start(sensorManager);
-
-        setPeakRefreshRate(Float.POSITIVE_INFINITY);
-
-        Vote vote = director.getVote(DISPLAY_ID,
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
                 Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
-        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
-                /* frameRateHigh= */ highestRefreshRate);
-
-        // The highest refresh rate of the display changes
-        highestRefreshRate = 140;
-        doReturn(highestRefreshRate).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
-        director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);
-
-        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
-        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
-                /* frameRateHigh= */ highestRefreshRate);
+        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+                peakRefreshRate);
     }
 
     @Test
     public void testMinRefreshRate_FlagEnabled() {
         when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                 .thenReturn(true);
-        float highestRefreshRate1 = 130;
-        float highestRefreshRate2 = 132;
-        doReturn(highestRefreshRate1).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
-        doReturn(highestRefreshRate2).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID_2));
+        float highestRefreshRate = 130;
+        doReturn(highestRefreshRate).when(() ->
+                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
         DisplayModeDirector director =
                 createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
         director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -1650,12 +1607,9 @@
 
         setMinRefreshRate(Float.POSITIVE_INFINITY);
 
-        Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
-        Vote vote2 = director.getVote(DISPLAY_ID_2,
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
                 Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
-        assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ highestRefreshRate1,
-                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
-        assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ highestRefreshRate2,
+        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
                 /* frameRateHigh= */ Float.POSITIVE_INFINITY);
     }
 
@@ -1674,44 +1628,13 @@
 
         setMinRefreshRate(minRefreshRate);
 
-        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+                Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
         assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate,
                 /* frameRateHigh= */ Float.POSITIVE_INFINITY);
     }
 
     @Test
-    public void testMinRefreshRate_DisplayChanged() {
-        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
-                .thenReturn(true);
-        float highestRefreshRate = 130;
-        doReturn(highestRefreshRate).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
-        DisplayModeDirector director =
-                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
-        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
-
-        Sensor lightSensor = createLightSensor();
-        SensorManager sensorManager = createMockSensorManager(lightSensor);
-        director.start(sensorManager);
-
-        setMinRefreshRate(Float.POSITIVE_INFINITY);
-
-        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
-        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
-                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
-
-        // The highest refresh rate of the display changes
-        highestRefreshRate = 140;
-        doReturn(highestRefreshRate).when(() ->
-                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
-        director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);
-
-        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
-        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
-                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
-    }
-
-    @Test
     public void testSensorRegistration() {
         // First, configure brightness zones or DMD won't register for sensor data.
         final FakeDeviceConfig config = mInjector.getDeviceConfig();
@@ -3406,7 +3329,7 @@
     public static class FakesInjector implements DisplayModeDirector.Injector {
         private final FakeDeviceConfig mDeviceConfig;
         private final DisplayInfo mDisplayInfo;
-        private final Map<Integer, Display> mDisplays;
+        private final Display mDisplay;
         private boolean mDisplayInfoValid = true;
         private final DisplayManagerInternal mDisplayManagerInternal;
         private final StatusBarManagerInternal mStatusBarManagerInternal;
@@ -3427,8 +3350,7 @@
             mDisplayInfo.defaultModeId = MODE_ID;
             mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
                     800, 600, /* refreshRate= */ 60)};
-            mDisplays = Map.of(DISPLAY_ID, createDisplay(DISPLAY_ID),
-                    DISPLAY_ID_2, createDisplay(DISPLAY_ID_2));
+            mDisplay = createDisplay(DISPLAY_ID);
             mDisplayManagerInternal = displayManagerInternal;
             mStatusBarManagerInternal = statusBarManagerInternal;
             mSensorManagerInternal = sensorManagerInternal;
@@ -3459,12 +3381,12 @@
 
         @Override
         public Display getDisplay(int displayId) {
-            return mDisplays.get(displayId);
+            return mDisplay;
         }
 
         @Override
         public Display[] getDisplays() {
-            return mDisplays.values().toArray(new Display[0]);
+            return new Display[] { mDisplay };
         }
 
         @Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssLocationProviderTest.java
new file mode 100644
index 0000000..c5e6824
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssLocationProviderTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2023 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.location.gnss;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.AlarmManager;
+import android.app.AppOpsManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.location.GnssCapabilities;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.flags.Flags;
+import android.location.provider.ProviderRequest;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+import com.android.server.LocalServices;
+import com.android.server.location.gnss.hal.FakeGnssHal;
+import com.android.server.location.gnss.hal.GnssNative;
+import com.android.server.location.injector.Injector;
+import com.android.server.location.injector.TestInjector;
+import com.android.server.timedetector.TimeDetectorInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.quality.Strictness;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+@Presubmit
+@androidx.test.filters.SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GnssLocationProviderTest {
+
+    @Rule
+    public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
+            .setStrictness(Strictness.WARN)
+            .mockStatic(Settings.Global.class)
+            .build();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    private @Mock Context mContext;
+    private @Mock LocationManagerInternal mLocationManagerInternal;
+    private @Mock LocationManager mLocationManager;
+    private @Mock TimeDetectorInternal mTimeDetectorInternal;
+    private @Mock GnssConfiguration mMockConfiguration;
+    private @Mock GnssMetrics mGnssMetrics;
+    private @Mock PowerManager mPowerManager;
+    private @Mock TelephonyManager mTelephonyManager;
+    private @Mock AppOpsManager mAppOpsManager;
+    private @Mock AlarmManager mAlarmManager;
+    private @Mock PowerManager.WakeLock mWakeLock;
+    private @Mock ContentResolver mContentResolver;
+    private @Mock UserManager mUserManager;
+    private @Mock UserHandle mUserHandle;
+    private Set<UserHandle> mUserHandleSet = new HashSet<>();
+
+    private GnssNative mGnssNative;
+
+    private GnssLocationProvider mTestProvider;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        doReturn("mypackage").when(mContext).getPackageName();
+        doReturn("attribution").when(mContext).getAttributionTag();
+        doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+        doReturn(mPowerManager).when(mContext).getSystemService("power");
+        doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
+        doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
+        doReturn(mAlarmManager).when(mContext).getSystemService(Context.ALARM_SERVICE);
+        doReturn(mLocationManager).when(mContext).getSystemService(LocationManager.class);
+        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+        mUserHandleSet.add(mUserHandle);
+        doReturn(true).when(mLocationManager).isLocationEnabledForUser(eq(mUserHandle));
+        doReturn(mUserHandleSet).when(mUserManager).getVisibleUsers();
+        doReturn(mContentResolver).when(mContext).getContentResolver();
+        doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+        LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
+        LocalServices.addService(TimeDetectorInternal.class, mTimeDetectorInternal);
+        FakeGnssHal fakeGnssHal = new FakeGnssHal();
+        GnssNative.setGnssHalForTest(fakeGnssHal);
+        Injector injector = new TestInjector(mContext);
+        mGnssNative = spy(Objects.requireNonNull(
+                GnssNative.create(injector, mMockConfiguration)));
+        doReturn(true).when(mGnssNative).init();
+        GnssCapabilities gnssCapabilities = new GnssCapabilities.Builder().setHasScheduling(
+                true).build();
+        doReturn(gnssCapabilities).when(mGnssNative).getCapabilities();
+
+        mTestProvider = new GnssLocationProvider(mContext, mGnssNative, mGnssMetrics);
+        mGnssNative.register();
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(LocationManagerInternal.class);
+        LocalServices.removeServiceForTest(TimeDetectorInternal.class);
+    }
+
+    @Test
+    public void testStartNavigating() {
+        ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis(
+                0).build();
+
+        mTestProvider.onSetRequest(providerRequest);
+        verify(mGnssNative).start();
+    }
+
+    @Test
+    public void testUpdateRequirements_sameRequest() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_GNSS_CALL_STOP_BEFORE_SET_POSITION_MODE);
+        ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis(
+                0).build();
+
+        mTestProvider.onSetRequest(providerRequest);
+        verify(mGnssNative).start();
+
+        // set the same request
+        mTestProvider.onSetRequest(providerRequest);
+        verify(mGnssNative, never()).stop();
+        verify(mGnssNative, times(1)).start();
+    }
+
+    @Test
+    public void testUpdateRequirements_differentRequest() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_GNSS_CALL_STOP_BEFORE_SET_POSITION_MODE);
+        ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis(
+                0).build();
+
+        mTestProvider.onSetRequest(providerRequest);
+        verify(mGnssNative).start();
+
+        // set a different request
+        providerRequest = new ProviderRequest.Builder().setIntervalMillis(2000).build();
+        mTestProvider.onSetRequest(providerRequest);
+        verify(mGnssNative).stop();
+        verify(mGnssNative, times(2)).start();
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
index 931b38d..f8fe97e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
@@ -22,12 +22,14 @@
 import android.content.pm.PackageManager.PERMISSION_GRANTED
 import android.content.pm.UserInfo
 import android.os.Build
+import android.os.UserHandle
 import android.os.UserHandle.USER_SYSTEM
 import android.util.Log
 import com.android.server.testutils.any
 import com.android.server.testutils.spy
 import com.android.server.testutils.whenever
 import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertFalse
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -177,4 +179,13 @@
 
         assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_INTERNAL_ERROR)
     }
+
+    @Test
+    fun deletePackageLIFWithNonExistantPackage_isFalse() {
+        val dph = DeletePackageHelper(mPms, mock(RemovePackageHelper::class.java),
+                                      mock(BroadcastHelper::class.java))
+        val result = dph.deletePackageLIF("a.nonexistent.package", UserHandle.of(USER_SYSTEM), true,
+                                          intArrayOf(0), 0, PackageRemovedInfo(), true)
+        assertFalse(result)
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
index 01922e0..edfe1b4 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
@@ -40,6 +40,7 @@
 import android.testing.TestableLooper;
 import android.view.Surface;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -77,6 +78,11 @@
         when(mVirtualCameraServiceMock.registerCamera(any(), any())).thenReturn(true);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        mVirtualCameraController.close();
+    }
+
     @Test
     public void registerCamera_registersCamera() throws Exception {
         mVirtualCameraController.registerCamera(createVirtualCameraConfig(
@@ -95,6 +101,8 @@
     public void unregisterCamera_unregistersCamera() throws Exception {
         VirtualCameraConfig config = createVirtualCameraConfig(
                 CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT, CAMERA_DISPLAY_NAME_RES_ID_1);
+        mVirtualCameraController.registerCamera(config);
+
         mVirtualCameraController.unregisterCamera(config);
 
         verify(mVirtualCameraServiceMock).unregisterCamera(any());
@@ -107,9 +115,10 @@
         mVirtualCameraController.registerCamera(createVirtualCameraConfig(
                 CAMERA_WIDTH_2, CAMERA_HEIGHT_2, CAMERA_FORMAT, CAMERA_DISPLAY_NAME_RES_ID_2));
 
+        mVirtualCameraController.close();
+
         ArgumentCaptor<VirtualCameraConfiguration> configurationCaptor =
                 ArgumentCaptor.forClass(VirtualCameraConfiguration.class);
-        mVirtualCameraController.close();
         verify(mVirtualCameraServiceMock, times(2)).registerCamera(any(),
                 configurationCaptor.capture());
         List<VirtualCameraConfiguration> virtualCameraConfigurations =
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index d000605..32082e3 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -28,6 +28,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -1449,4 +1450,21 @@
         checkPreparationPhasesForPackage(currentSdkPackage.packageName,
                 1 /* first preparation phase */);
     }
+
+    @Test
+    @RequiresFlagsEnabled("android.webkit.update_service_v2")
+    public void testDefaultWebViewPackageIsTheFirstAvailableByDefault() {
+        String nonDefaultPackage = "nonDefaultPackage";
+        String defaultPackage1 = "defaultPackage1";
+        String defaultPackage2 = "defaultPackage2";
+        WebViewProviderInfo[] packages =
+                new WebViewProviderInfo[] {
+                    new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
+                    new WebViewProviderInfo(defaultPackage1, "", true, false, null),
+                    new WebViewProviderInfo(defaultPackage2, "", true, false, null)
+                };
+        setupWithPackages(packages);
+        assertEquals(
+                defaultPackage1, mWebViewUpdateServiceImpl.getDefaultWebViewPackage().packageName);
+    }
 }
diff --git a/services/tests/wmtests/AndroidTest.xml b/services/tests/wmtests/AndroidTest.xml
index f8ebead..46e87dc 100644
--- a/services/tests/wmtests/AndroidTest.xml
+++ b/services/tests/wmtests/AndroidTest.xml
@@ -30,4 +30,8 @@
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false" />
     </test>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="settings put secure immersive_mode_confirmations confirmed" />
+    </target_preparer>
 </configuration>
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index dade3b9..71447e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -2015,6 +2015,9 @@
         transition.collect(leafTaskA);
         rootTaskA.moveToFront("test", leafTaskA);
 
+        // Test has order changes, a shallow check of order changes
+        assertTrue(transition.hasOrderChanges());
+
         // All the tasks were already visible, so there shouldn't be any changes
         ArrayList<Transition.ChangeInfo> targets = Transition.calculateTargets(
                 participants, changes);
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
index 356e1fa..8354d98 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
@@ -39,5 +39,5 @@
 private fun ClassNodes.isAidlClass(className: String): Boolean {
     return hasClass(className) &&
             hasClass("$className\$Stub") &&
-            hasClass("$className\$Proxy")
+            hasClass("$className\$Stub\$Proxy")
 }
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 214de59..3956893 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -223,16 +223,16 @@
     java.lang.annotation.Target(
       value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD]
     )
-## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
   Compiled from "IPretendingAidl.java"
-public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
   minor version: 0
   major version: 61
   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
-  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
   super_class: #x                         // java/lang/Object
   interfaces: 0, fields: 0, methods: 2, attributes: 3
-  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
     descriptor: ()V
     flags: (0x0001) ACC_PUBLIC
     Code:
@@ -243,7 +243,7 @@
       LineNumberTable:
       LocalVariableTable:
         Start  Length  Slot  Name   Signature
-            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy;
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
 
   public static int addTwo(int);
     descriptor: (I)I
@@ -262,7 +262,8 @@
 SourceFile: "IPretendingAidl.java"
 NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
 InnerClasses:
-  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;          // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
   Compiled from "IPretendingAidl.java"
 public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
@@ -303,6 +304,7 @@
 NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
 InnerClasses:
   public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
   Compiled from "IPretendingAidl.java"
 public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
@@ -315,11 +317,11 @@
 }
 SourceFile: "IPretendingAidl.java"
 NestMembers:
-  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
 InnerClasses:
-  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
-  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 9031228..9349355 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -1,13 +1,13 @@
-## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
   Compiled from "IPretendingAidl.java"
-public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
   minor version: 0
   major version: 61
   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
-  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
   super_class: #x                         // java/lang/Object
   interfaces: 0, fields: 0, methods: 2, attributes: 4
-  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
     descriptor: ()V
     flags: (0x0001) ACC_PUBLIC
     Code:
@@ -30,7 +30,8 @@
          x: athrow
 }
 InnerClasses:
-  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -71,6 +72,7 @@
 }
 InnerClasses:
   public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -89,8 +91,8 @@
   interfaces: 0, fields: 0, methods: 0, attributes: 4
 }
 InnerClasses:
-  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
-  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -98,8 +100,8 @@
   x: #x()
     com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
 NestMembers:
-  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index e01f49b..4f8c408e 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -205,16 +205,16 @@
     java.lang.annotation.Retention(
       value=Ljava/lang/annotation/RetentionPolicy;.CLASS
     )
-## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
   Compiled from "IPretendingAidl.java"
-public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
   minor version: 0
   major version: 61
   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
-  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
   super_class: #x                         // java/lang/Object
   interfaces: 0, fields: 0, methods: 2, attributes: 4
-  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
     descriptor: ()V
     flags: (0x0001) ACC_PUBLIC
     Code:
@@ -225,7 +225,7 @@
       LineNumberTable:
       LocalVariableTable:
         Start  Length  Slot  Name   Signature
-            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy;
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
 
   public static int addTwo(int);
     descriptor: (I)I
@@ -242,7 +242,8 @@
             0       4     0     a   I
 }
 InnerClasses:
-  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -288,6 +289,7 @@
 }
 InnerClasses:
   public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -306,8 +308,8 @@
   interfaces: 0, fields: 0, methods: 0, attributes: 4
 }
 InnerClasses:
-  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
-  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -315,8 +317,8 @@
   x: #x()
     com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
 NestMembers:
-  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 9031228..9349355 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -1,13 +1,13 @@
-## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
   Compiled from "IPretendingAidl.java"
-public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
   minor version: 0
   major version: 61
   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
-  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
   super_class: #x                         // java/lang/Object
   interfaces: 0, fields: 0, methods: 2, attributes: 4
-  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
     descriptor: ()V
     flags: (0x0001) ACC_PUBLIC
     Code:
@@ -30,7 +30,8 @@
          x: athrow
 }
 InnerClasses:
-  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -71,6 +72,7 @@
 }
 InnerClasses:
   public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -89,8 +91,8 @@
   interfaces: 0, fields: 0, methods: 0, attributes: 4
 }
 InnerClasses:
-  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
-  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -98,8 +100,8 @@
   x: #x()
     com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
 NestMembers:
-  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 5246355..5ff3cde 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -289,13 +289,13 @@
     java.lang.annotation.Retention(
       value=Ljava/lang/annotation/RetentionPolicy;.CLASS
     )
-## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy.class
   Compiled from "IPretendingAidl.java"
-public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy
   minor version: 0
   major version: 61
   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
-  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
   super_class: #x                         // java/lang/Object
   interfaces: 0, fields: 0, methods: 3, attributes: 4
   private static {};
@@ -303,17 +303,17 @@
     flags: (0x000a) ACC_PRIVATE, ACC_STATIC
     Code:
       stack=2, locals=0, args_size=0
-         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
          x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
          x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
          x: return
 
-  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy();
     descriptor: ()V
     flags: (0x0001) ACC_PUBLIC
     Code:
       stack=4, locals=1, args_size=1
-         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
          x: ldc           #x                 // String <init>
          x: ldc           #x                 // String ()V
          x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
@@ -324,14 +324,14 @@
       LineNumberTable:
       LocalVariableTable:
         Start  Length  Slot  Name   Signature
-           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy;
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy;
 
   public static int addTwo(int);
     descriptor: (I)I
     flags: (0x0009) ACC_PUBLIC, ACC_STATIC
     Code:
       stack=4, locals=1, args_size=1
-         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
          x: ldc           #x                 // String addTwo
          x: ldc           #x                 // String (I)I
          x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
@@ -346,7 +346,8 @@
            11       4     0     a   I
 }
 InnerClasses:
-  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;          // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -412,6 +413,7 @@
 }
 InnerClasses:
   public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -439,8 +441,8 @@
          x: return
 }
 InnerClasses:
-  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
   public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+  public static #x= #x of #x;          // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
 SourceFile: "IPretendingAidl.java"
 RuntimeVisibleAnnotations:
   x: #x()
@@ -448,8 +450,8 @@
   x: #x()
     com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
 NestMembers:
-  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
index 583e13c..0a07c2b 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
@@ -25,11 +25,12 @@
         public static int addOne(int a) {
             return a + 1;
         }
-    }
 
-    public static class Proxy {
-        public static int addTwo(int a) {
-            return a + 2;
+        public static class Proxy {
+            public static int addTwo(int a) {
+                return a + 2;
+            }
         }
     }
+
 }
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index 0d52791..d350105 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -289,6 +289,6 @@
     @Test
     public void testAidlHeuristics() {
         assertThat(IPretendingAidl.Stub.addOne(1)).isEqualTo(2);
-        assertThat(IPretendingAidl.Proxy.addTwo(1)).isEqualTo(3);
+        assertThat(IPretendingAidl.Stub.Proxy.addTwo(1)).isEqualTo(3);
     }
 }