Merge "Update documentation for WindowManager.LayoutParams#preferredRefreshRate" into udc-dev
diff --git a/core/api/current.txt b/core/api/current.txt
index 79123c7..771d56c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6623,6 +6623,7 @@
     ctor public Notification.MediaStyle();
     ctor @Deprecated public Notification.MediaStyle(android.app.Notification.Builder);
     method public android.app.Notification.MediaStyle setMediaSession(android.media.session.MediaSession.Token);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.app.Notification.MediaStyle setRemotePlaybackInfo(@NonNull CharSequence, @DrawableRes int, @Nullable android.app.PendingIntent);
     method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...);
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0a893f0..ce5723b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -968,10 +968,6 @@
     field public static final int SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY = 11; // 0xb
   }
 
-  public static class Notification.MediaStyle extends android.app.Notification.Style {
-    method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.app.Notification.MediaStyle setRemotePlaybackInfo(@NonNull CharSequence, @DrawableRes int, @Nullable android.app.PendingIntent);
-  }
-
   public static final class Notification.TvExtender implements android.app.Notification.Extender {
     ctor public Notification.TvExtender();
     ctor public Notification.TvExtender(android.app.Notification);
@@ -9984,6 +9980,7 @@
   public final class HotspotNetwork implements android.os.Parcelable {
     method public int describeContents();
     method public long getDeviceId();
+    method @NonNull public android.os.Bundle getExtras();
     method public int getHostNetworkType();
     method @Nullable public String getHotspotBssid();
     method @NonNull public java.util.Set<java.lang.Integer> getHotspotSecurityTypes();
@@ -10003,6 +10000,7 @@
     method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder addHotspotSecurityType(int);
     method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork build();
     method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setDeviceId(long);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setExtras(@NonNull android.os.Bundle);
     method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHostNetworkType(int);
     method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotBssid(@NonNull String);
     method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotSsid(@NonNull String);
@@ -10039,6 +10037,7 @@
 
   public final class KnownNetwork implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public android.os.Bundle getExtras();
     method @Nullable public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo getNetworkProviderInfo();
     method public int getNetworkSource();
     method @NonNull public java.util.Set<java.lang.Integer> getSecurityTypes();
@@ -10054,6 +10053,7 @@
     ctor public KnownNetwork.Builder();
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder addSecurityType(int);
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork build();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setExtras(@NonNull android.os.Bundle);
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkProviderInfo(@Nullable android.net.wifi.sharedconnectivity.app.NetworkProviderInfo);
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkSource(int);
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setSsid(@NonNull String);
@@ -10085,6 +10085,7 @@
     method @IntRange(from=0, to=3) public int getConnectionStrength();
     method @NonNull public String getDeviceName();
     method public int getDeviceType();
+    method @NonNull public android.os.Bundle getExtras();
     method @NonNull public String getModelName();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.NetworkProviderInfo> CREATOR;
@@ -10103,6 +10104,7 @@
     method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setConnectionStrength(@IntRange(from=0, to=3) int);
     method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceName(@NonNull String);
     method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceType(int);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setExtras(@NonNull android.os.Bundle);
     method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setModelName(@NonNull String);
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 445b957..6bfaa35 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -516,6 +516,10 @@
 
 package android.app.admin {
 
+  public final class AccountTypePolicyKey extends android.app.admin.PolicyKey {
+    ctor public AccountTypePolicyKey(@NonNull String, @NonNull String);
+  }
+
   public final class DeviceAdminAuthority extends android.app.admin.Authority {
     field @NonNull public static final android.app.admin.DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY;
   }
@@ -612,6 +616,10 @@
     field @NonNull public static final android.app.admin.FlagUnion FLAG_UNION;
   }
 
+  public final class IntentFilterPolicyKey extends android.app.admin.PolicyKey {
+    ctor public IntentFilterPolicyKey(@NonNull String, @NonNull android.content.IntentFilter);
+  }
+
   public final class MostRecent<V> extends android.app.admin.ResolutionMechanism<V> {
     ctor public MostRecent();
     method public int describeContents();
@@ -627,6 +635,14 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRestrictive<?>> CREATOR;
   }
 
+  public final class PackagePermissionPolicyKey extends android.app.admin.PolicyKey {
+    ctor public PackagePermissionPolicyKey(@NonNull String, @NonNull String, @NonNull String);
+  }
+
+  public final class PackagePolicyKey extends android.app.admin.PolicyKey {
+    ctor public PackagePolicyKey(@NonNull String, @NonNull String);
+  }
+
   public final class PolicyState<V> implements android.os.Parcelable {
     method @NonNull public android.app.admin.ResolutionMechanism<V> getResolutionMechanism();
   }
@@ -676,6 +692,10 @@
     method public int getOperation();
   }
 
+  public final class UserRestrictionPolicyKey extends android.app.admin.PolicyKey {
+    ctor public UserRestrictionPolicyKey(@NonNull String, @NonNull String);
+  }
+
 }
 
 package android.app.assist {
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index a81ef18..d0ce701 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -69,7 +69,7 @@
      * backing field for backgroundPauseDelay property. This could be simply a hardcoded
      * value in AnimationHandler, but it is useful to be able to change the value in tests.
      */
-    private static long sBackgroundPauseDelay = 10000;
+    private static long sBackgroundPauseDelay = 1000;
 
     /**
      * Sets the duration for delaying pausing animators when apps go into the background.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0e89f57..502ef0d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -9163,10 +9163,7 @@
          *                   {@code null}, in which case the output switcher will be disabled.
          *                   This intent should open an Activity or it will be ignored.
          * @return MediaStyle
-         *
-         * @hide
          */
-        @SystemApi
         @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)
         @NonNull
         public MediaStyle setRemotePlaybackInfo(@NonNull CharSequence deviceName,
diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java
index 6417cd4..9e376a7 100644
--- a/core/java/android/app/admin/AccountTypePolicyKey.java
+++ b/core/java/android/app/admin/AccountTypePolicyKey.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.Parcel;
 
@@ -49,6 +50,7 @@
     /**
      * @hide
      */
+    @TestApi
     public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {
         super(key);
         mAccountType = Objects.requireNonNull((accountType));
diff --git a/core/java/android/app/admin/IntentFilterPolicyKey.java b/core/java/android/app/admin/IntentFilterPolicyKey.java
index b0af4cd..30aad96 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -49,6 +50,7 @@
     /**
      * @hide
      */
+    @TestApi
     public IntentFilterPolicyKey(@NonNull String identifier, @NonNull IntentFilter filter) {
         super(identifier);
         mFilter = Objects.requireNonNull(filter);
diff --git a/core/java/android/app/admin/PackagePermissionPolicyKey.java b/core/java/android/app/admin/PackagePermissionPolicyKey.java
index 08c4224..7fd514c 100644
--- a/core/java/android/app/admin/PackagePermissionPolicyKey.java
+++ b/core/java/android/app/admin/PackagePermissionPolicyKey.java
@@ -24,6 +24,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -53,6 +54,7 @@
     /**
      * @hide
      */
+    @TestApi
     public PackagePermissionPolicyKey(@NonNull String identifier, @NonNull String packageName,
             @NonNull String permissionName) {
         super(identifier);
diff --git a/core/java/android/app/admin/PackagePolicyKey.java b/core/java/android/app/admin/PackagePolicyKey.java
index b2a8d5d..2ab00bc 100644
--- a/core/java/android/app/admin/PackagePolicyKey.java
+++ b/core/java/android/app/admin/PackagePolicyKey.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -50,6 +51,7 @@
     /**
      * @hide
      */
+    @TestApi
     public PackagePolicyKey(@NonNull String key, @NonNull String packageName) {
         super(key);
         mPackageName = Objects.requireNonNull((packageName));
diff --git a/core/java/android/app/admin/UserRestrictionPolicyKey.java b/core/java/android/app/admin/UserRestrictionPolicyKey.java
index 880b58b..aeb2380 100644
--- a/core/java/android/app/admin/UserRestrictionPolicyKey.java
+++ b/core/java/android/app/admin/UserRestrictionPolicyKey.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.Parcel;
 
@@ -40,6 +41,7 @@
     /**
      * @hide
      */
+    @TestApi
     public UserRestrictionPolicyKey(@NonNull String identifier, @NonNull String restriction) {
         super(identifier);
         mRestriction = Objects.requireNonNull(restriction);
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index fe10b7f..27f6a26 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -31,6 +31,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
+import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -311,20 +312,27 @@
             super.onLayout(changed, left, top, right, bottom);
         } catch (final RuntimeException e) {
             Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e);
-            removeViewInLayout(mView);
-            View child = getErrorView();
-            prepareView(child);
-            addViewInLayout(child, 0, child.getLayoutParams());
-            measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
-            child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
-                    child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
-            mView = child;
-            mViewMode = VIEW_MODE_ERROR;
+            handleViewError();
         }
     }
 
     /**
+     * Remove bad view and replace with error message view
+     */
+    private void handleViewError() {
+        removeViewInLayout(mView);
+        View child = getErrorView();
+        prepareView(child);
+        addViewInLayout(child, 0, child.getLayoutParams());
+        measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
+        child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
+                child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
+        mView = child;
+        mViewMode = VIEW_MODE_ERROR;
+    }
+
+    /**
      * Provide guidance about the size of this widget to the AppWidgetManager. The widths and
      * heights should correspond to the full area the AppWidgetHostView is given. Padding added by
      * the framework will be accounted for automatically. This information gets embedded into the
@@ -953,4 +961,15 @@
             reapplyLastRemoteViews();
         }
     }
+
+    @Override
+    protected void dispatchDraw(@NonNull Canvas canvas) {
+        try {
+            super.dispatchDraw(canvas);
+        } catch (Exception e) {
+            // Catch draw exceptions that may be caused by RemoteViews
+            Log.e(TAG, "Drawing view failed: " + e);
+            post(this::handleViewError);
+        }
+    }
 }
diff --git a/core/java/android/hardware/input/InputDeviceLightsManager.java b/core/java/android/hardware/input/InputDeviceLightsManager.java
index 802e6dd..f4ee9a2 100644
--- a/core/java/android/hardware/input/InputDeviceLightsManager.java
+++ b/core/java/android/hardware/input/InputDeviceLightsManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityThread;
+import android.content.Context;
 import android.hardware.lights.Light;
 import android.hardware.lights.LightState;
 import android.hardware.lights.LightsManager;
@@ -30,22 +31,22 @@
 import java.util.List;
 
 /**
- * LightsManager manages an input device's lights {@link android.hardware.input.Light}.
+ * LightsManager manages an input device's lights {@link android.hardware.lights.Light}
  */
 class InputDeviceLightsManager extends LightsManager {
     private static final String TAG = "InputDeviceLightsManager";
     private static final boolean DEBUG = false;
 
-    private final InputManager mInputManager;
+    private final InputManagerGlobal mGlobal;
 
     // The input device ID.
     private final int mDeviceId;
     // Package name
     private final String mPackageName;
 
-    InputDeviceLightsManager(InputManager inputManager, int deviceId) {
-        super(ActivityThread.currentActivityThread().getSystemContext());
-        mInputManager = inputManager;
+    InputDeviceLightsManager(Context context, int deviceId) {
+        super(context);
+        mGlobal = InputManagerGlobal.getInstance();
         mDeviceId = deviceId;
         mPackageName = ActivityThread.currentPackageName();
     }
@@ -57,7 +58,7 @@
      */
     @Override
     public @NonNull List<Light> getLights() {
-        return mInputManager.getLights(mDeviceId);
+        return mGlobal.getLights(mDeviceId);
     }
 
     /**
@@ -68,7 +69,7 @@
     @Override
     public @NonNull LightState getLightState(@NonNull Light light) {
         Preconditions.checkNotNull(light);
-        return mInputManager.getLightState(mDeviceId, light);
+        return mGlobal.getLightState(mDeviceId, light);
     }
 
     /**
@@ -77,7 +78,7 @@
     @Override
     public @NonNull LightsSession openSession() {
         final LightsSession session = new InputDeviceLightsSession();
-        mInputManager.openLightSession(mDeviceId, mPackageName, session.getToken());
+        mGlobal.openLightSession(mDeviceId, mPackageName, session.getToken());
         return session;
     }
 
@@ -113,7 +114,7 @@
             Preconditions.checkNotNull(request);
             Preconditions.checkArgument(!mClosed);
 
-            mInputManager.requestLights(mDeviceId, request, getToken());
+            mGlobal.requestLights(mDeviceId, request, getToken());
         }
 
         /**
@@ -122,7 +123,7 @@
         @Override
         public void close() {
             if (!mClosed) {
-                mInputManager.closeLightSession(mDeviceId, getToken());
+                mGlobal.closeLightSession(mDeviceId, getToken());
                 mClosed = true;
                 mCloseGuard.close();
             }
diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java
index ce6b523..9c18260 100644
--- a/core/java/android/hardware/input/InputDeviceVibrator.java
+++ b/core/java/android/hardware/input/InputDeviceVibrator.java
@@ -45,14 +45,14 @@
     private final int mDeviceId;
     private final VibratorInfo mVibratorInfo;
     private final Binder mToken;
-    private final InputManager mInputManager;
+    private final InputManagerGlobal mGlobal;
 
     @GuardedBy("mDelegates")
     private final ArrayMap<OnVibratorStateChangedListener,
             OnVibratorStateChangedListenerDelegate> mDelegates = new ArrayMap<>();
 
-    InputDeviceVibrator(InputManager inputManager, int deviceId, int vibratorId) {
-        mInputManager = inputManager;
+    InputDeviceVibrator(int deviceId, int vibratorId) {
+        mGlobal = InputManagerGlobal.getInstance();
         mDeviceId = deviceId;
         mVibratorInfo = new VibratorInfo.Builder(vibratorId)
                 .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
@@ -93,7 +93,7 @@
 
     @Override
     public boolean isVibrating() {
-        return mInputManager.isVibrating(mDeviceId);
+        return mGlobal.isVibrating(mDeviceId);
     }
 
     /**
@@ -132,7 +132,7 @@
 
             final OnVibratorStateChangedListenerDelegate delegate =
                     new OnVibratorStateChangedListenerDelegate(listener, executor);
-            if (!mInputManager.registerVibratorStateListener(mDeviceId, delegate)) {
+            if (!mGlobal.registerVibratorStateListener(mDeviceId, delegate)) {
                 Log.w(TAG, "Failed to register vibrate state listener");
                 return;
             }
@@ -156,7 +156,7 @@
             if (mDelegates.containsKey(listener)) {
                 final OnVibratorStateChangedListenerDelegate delegate = mDelegates.get(listener);
 
-                if (!mInputManager.unregisterVibratorStateListener(mDeviceId, delegate)) {
+                if (!mGlobal.unregisterVibratorStateListener(mDeviceId, delegate)) {
                     Log.w(TAG, "Failed to unregister vibrate state listener");
                     return;
                 }
@@ -176,12 +176,12 @@
     @Override
     public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect, String reason,
             @NonNull VibrationAttributes attributes) {
-        mInputManager.vibrate(mDeviceId, effect, mToken);
+        mGlobal.vibrate(mDeviceId, effect, mToken);
     }
 
     @Override
     public void cancel() {
-        mInputManager.cancelVibrate(mDeviceId, mToken);
+        mGlobal.cancelVibrate(mDeviceId, mToken);
     }
 
     @Override
diff --git a/core/java/android/hardware/input/InputDeviceVibratorManager.java b/core/java/android/hardware/input/InputDeviceVibratorManager.java
index d77f9c3..64b56677 100644
--- a/core/java/android/hardware/input/InputDeviceVibratorManager.java
+++ b/core/java/android/hardware/input/InputDeviceVibratorManager.java
@@ -40,7 +40,7 @@
     private static final boolean DEBUG = false;
 
     private final Binder mToken;
-    private final InputManager mInputManager;
+    private final InputManagerGlobal mGlobal;
 
     // The input device Id.
     private final int mDeviceId;
@@ -48,8 +48,8 @@
     @GuardedBy("mVibrators")
     private final SparseArray<Vibrator> mVibrators = new SparseArray<>();
 
-    public InputDeviceVibratorManager(InputManager inputManager, int deviceId) {
-        mInputManager = inputManager;
+    public InputDeviceVibratorManager(int deviceId) {
+        mGlobal = InputManagerGlobal.getInstance();
         mDeviceId = deviceId;
         mToken = new Binder();
 
@@ -61,10 +61,10 @@
             mVibrators.clear();
             InputDevice inputDevice = InputDevice.getDevice(mDeviceId);
             final int[] vibratorIds =
-                    mInputManager.getVibratorIds(mDeviceId);
+                    mGlobal.getVibratorIds(mDeviceId);
             for (int i = 0; i < vibratorIds.length; i++) {
                 mVibrators.put(vibratorIds[i],
-                        new InputDeviceVibrator(mInputManager, mDeviceId, vibratorIds[i]));
+                        new InputDeviceVibrator(mDeviceId, vibratorIds[i]));
             }
         }
     }
@@ -127,12 +127,12 @@
     @Override
     public void vibrate(int uid, String opPkg, @NonNull CombinedVibration effect,
             String reason, @Nullable VibrationAttributes attributes) {
-        mInputManager.vibrate(mDeviceId, effect, mToken);
+        mGlobal.vibrate(mDeviceId, effect, mToken);
     }
 
     @Override
     public void cancel() {
-        mInputManager.cancelVibrate(mDeviceId, mToken);
+        mGlobal.cancelVibrate(mDeviceId, mToken);
     }
 
     @Override
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 054ae21..5dc3825 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -33,21 +33,15 @@
 import android.content.Context;
 import android.hardware.BatteryState;
 import android.hardware.SensorManager;
-import android.hardware.lights.Light;
-import android.hardware.lights.LightState;
 import android.hardware.lights.LightsManager;
-import android.hardware.lights.LightsRequest;
 import android.os.Binder;
 import android.os.Build;
-import android.os.CombinedVibration;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IVibratorStateListener;
 import android.os.InputEventInjectionSync;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.VibratorManager;
 import android.util.Log;
@@ -1380,7 +1374,7 @@
      * @hide
      */
     public Vibrator getInputDeviceVibrator(int deviceId, int vibratorId) {
-        return new InputDeviceVibrator(this, deviceId, vibratorId);
+        return new InputDeviceVibrator(deviceId, vibratorId);
     }
 
     /**
@@ -1391,85 +1385,7 @@
      */
     @NonNull
     public VibratorManager getInputDeviceVibratorManager(int deviceId) {
-        return new InputDeviceVibratorManager(InputManager.this, deviceId);
-    }
-
-    /*
-     * Get the list of device vibrators
-     * @return The list of vibrators IDs
-     */
-    int[] getVibratorIds(int deviceId) {
-        try {
-            return mIm.getVibratorIds(deviceId);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
-    /*
-     * Perform vibration effect
-     */
-    void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
-        try {
-            mIm.vibrate(deviceId, effect, token);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
-    /*
-     * Perform combined vibration effect
-     */
-    void vibrate(int deviceId, CombinedVibration effect, IBinder token) {
-        try {
-            mIm.vibrateCombined(deviceId, effect, token);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
-    /*
-     * Cancel an ongoing vibration
-     */
-    void cancelVibrate(int deviceId, IBinder token) {
-        try {
-            mIm.cancelVibrate(deviceId, token);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
-    /*
-     * Check if input device is vibrating
-     */
-    boolean isVibrating(int deviceId)  {
-        try {
-            return mIm.isVibrating(deviceId);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Register input device vibrator state listener
-     */
-    boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
-        try {
-            return mIm.registerVibratorStateListener(deviceId, listener);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Unregister input device vibrator state listener
-     */
-    boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
-        try {
-            return mIm.unregisterVibratorStateListener(deviceId, listener);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
+        return new InputDeviceVibratorManager(deviceId);
     }
 
     /**
@@ -1499,77 +1415,7 @@
      */
     @NonNull
     public LightsManager getInputDeviceLightsManager(int deviceId) {
-        return new InputDeviceLightsManager(InputManager.this, deviceId);
-    }
-
-    /**
-     * Gets a list of light objects associated with an input device.
-     * @return The list of lights, never null.
-     */
-    @NonNull List<Light> getLights(int deviceId) {
-        try {
-            return mIm.getLights(deviceId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Returns the state of an input device light.
-     * @return the light state
-     */
-    @NonNull LightState getLightState(int deviceId, @NonNull Light light) {
-        try {
-            return mIm.getLightState(deviceId, light.getId());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Request to modify the states of multiple lights.
-     *
-     * @param request the settings for lights that should change
-     */
-    void requestLights(int deviceId, @NonNull LightsRequest request, IBinder token) {
-        try {
-            List<Integer> lightIdList = request.getLights();
-            int[] lightIds = new int[lightIdList.size()];
-            for (int i = 0; i < lightIds.length; i++) {
-                lightIds[i] = lightIdList.get(i);
-            }
-            List<LightState> lightStateList = request.getLightStates();
-            mIm.setLightStates(deviceId, lightIds,
-                    lightStateList.toArray(new LightState[0]),
-                    token);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Open light session for input device manager
-     *
-     * @param token The token for the light session
-     */
-    void openLightSession(int deviceId, String opPkg, @NonNull IBinder token) {
-        try {
-            mIm.openLightSession(deviceId, opPkg, token);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Close light session
-     *
-     */
-    void closeLightSession(int deviceId, @NonNull IBinder token) {
-        try {
-            mIm.closeLightSession(deviceId, token);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return new InputDeviceLightsManager(getContext(), deviceId);
     }
 
     /**
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 524d820..08d81bd 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -27,12 +27,18 @@
 import android.hardware.input.InputManager.InputDeviceListener;
 import android.hardware.input.InputManager.KeyboardBacklightListener;
 import android.hardware.input.InputManager.OnTabletModeChangedListener;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsRequest;
+import android.os.CombinedVibration;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IVibratorStateListener;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.VibrationEffect;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
@@ -903,4 +909,152 @@
             throw ex.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Gets a list of light objects associated with an input device.
+     * @return The list of lights, never null.
+     */
+    @NonNull List<Light> getLights(int deviceId) {
+        try {
+            return mIm.getLights(deviceId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the state of an input device light.
+     * @return the light state
+     */
+    @NonNull LightState getLightState(int deviceId, @NonNull Light light) {
+        try {
+            return mIm.getLightState(deviceId, light.getId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to modify the states of multiple lights.
+     *
+     * @param request the settings for lights that should change
+     */
+    void requestLights(int deviceId, @NonNull LightsRequest request, IBinder token) {
+        try {
+            List<Integer> lightIdList = request.getLights();
+            int[] lightIds = new int[lightIdList.size()];
+            for (int i = 0; i < lightIds.length; i++) {
+                lightIds[i] = lightIdList.get(i);
+            }
+            List<LightState> lightStateList = request.getLightStates();
+            mIm.setLightStates(deviceId, lightIds,
+                    lightStateList.toArray(new LightState[0]),
+                    token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Open light session for input device manager
+     *
+     * @param token The token for the light session
+     */
+    void openLightSession(int deviceId, String opPkg, @NonNull IBinder token) {
+        try {
+            mIm.openLightSession(deviceId, opPkg, token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Close light session
+     *
+     */
+    void closeLightSession(int deviceId, @NonNull IBinder token) {
+        try {
+            mIm.closeLightSession(deviceId, token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Get the list of device vibrators
+     * @return The list of vibrators IDs
+     */
+    int[] getVibratorIds(int deviceId) {
+        try {
+            return mIm.getVibratorIds(deviceId);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Perform vibration effect
+     */
+    void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
+        try {
+            mIm.vibrate(deviceId, effect, token);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Perform combined vibration effect
+     */
+    void vibrate(int deviceId, CombinedVibration effect, IBinder token) {
+        try {
+            mIm.vibrateCombined(deviceId, effect, token);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Cancel an ongoing vibration
+     */
+    void cancelVibrate(int deviceId, IBinder token) {
+        try {
+            mIm.cancelVibrate(deviceId, token);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Check if input device is vibrating
+     */
+    boolean isVibrating(int deviceId)  {
+        try {
+            return mIm.isVibrating(deviceId);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Register input device vibrator state listener
+     */
+    boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+        try {
+            return mIm.registerVibratorStateListener(deviceId, listener);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregister input device vibrator state listener
+     */
+    boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+        try {
+            return mIm.unregisterVibratorStateListener(deviceId, listener);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 127c7a0..05b6da4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11433,21 +11433,46 @@
         public @interface DeviceStateRotationLockSetting {
         }
 
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_UNKNOWN = -1;
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_FOLDED = 0;
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_HALF_FOLDED = 1;
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_UNFOLDED = 2;
+
+        /**
+         * The different postures that can be used as keys with
+         * {@link #DEVICE_STATE_ROTATION_LOCK}.
+         * @hide
+         */
+        @IntDef(prefix = {"DEVICE_STATE_ROTATION_KEY_"}, value = {
+                DEVICE_STATE_ROTATION_KEY_UNKNOWN,
+                DEVICE_STATE_ROTATION_KEY_FOLDED,
+                DEVICE_STATE_ROTATION_KEY_HALF_FOLDED,
+                DEVICE_STATE_ROTATION_KEY_UNFOLDED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface DeviceStateRotationLockKey {
+        }
+
         /**
          * Rotation lock setting keyed on device state.
          *
-         * This holds a serialized map using int keys that represent Device States and value of
+         * This holds a serialized map using int keys that represent postures in
+         * {@link DeviceStateRotationLockKey} and value of
          * {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that
-         * device state.
+         * posture.
          *
          * Serialized as key0:value0:key1:value1:...:keyN:valueN.
          *
          * Example: "0:1:1:2:2:1"
          * This example represents a map of:
          * <ul>
-         *     <li>0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
-         *     <li>1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
-         *     <li>2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
+         *     <li>DEVICE_STATE_ROTATION_KEY_FOLDED -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
+         *     <li>DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
+         *     <li>DEVICE_STATE_ROTATION_KEY_UNFOLDED -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
          * </ul>
          *
          * @hide
diff --git a/core/java/android/security/net/config/SystemCertificateSource.java b/core/java/android/security/net/config/SystemCertificateSource.java
index 13f7e5d..3a254c1 100644
--- a/core/java/android/security/net/config/SystemCertificateSource.java
+++ b/core/java/android/security/net/config/SystemCertificateSource.java
@@ -39,9 +39,13 @@
     }
 
     private static File getDirectory() {
-        // TODO(miguelaranda): figure out correct code path.
+        if ((System.getProperty("system.certs.enabled") != null)
+                && (System.getProperty("system.certs.enabled")).equals("true")) {
+            return new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
+        }
         File updatable_dir = new File("/apex/com.android.conscrypt/cacerts");
-        if (updatable_dir.exists() && !(updatable_dir.list().length == 0)) {
+        if (updatable_dir.exists()
+                && !(updatable_dir.list().length == 0)) {
             return updatable_dir;
         }
         return new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 48b112d..83de2a0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -294,7 +294,7 @@
     * an input channel where the client can receive input.
     */
     void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window,
-            in IBinder hostInputToken, int flags, int privateFlags, int type,
+            in IBinder hostInputToken, int flags, int privateFlags, int inputFeatures, int type,
             in IBinder windowToken, in IBinder focusGrantToken, String inputHandleName,
             out InputChannel outInputChannel);
 
@@ -302,7 +302,8 @@
      * Update the flags on an input channel associated with a particular surface.
      */
     oneway void updateInputChannel(in IBinder channelToken, int displayId,
-            in SurfaceControl surface, int flags, int privateFlags, in Region region);
+            in SurfaceControl surface, int flags, int privateFlags, int inputFeatures,
+            in Region region);
 
     /**
      * Transfer window focus to an embedded window if the calling window has focus.
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index b77b7a6..0560caf 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -139,7 +139,7 @@
                 try {
                     mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
                             state.mSurfaceControl, state.mParams.flags, state.mParams.privateFlags,
-                            state.mInputRegion);
+                            state.mParams.inputFeatures, state.mInputRegion);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to update surface input channel: ", e);
                 }
@@ -189,12 +189,13 @@
                     mRealWm.grantInputChannel(displayId,
                             new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
                             window, mHostInputToken,
-                            attrs.flags, attrs.privateFlags, attrs.type, attrs.token,
-                            mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
+                            attrs.flags, attrs.privateFlags, attrs.inputFeatures, attrs.type,
+                            attrs.token, mFocusGrantToken, attrs.getTitle().toString(),
+                            outInputChannel);
                 } else {
                     mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
-                            attrs.privateFlags, attrs.type, attrs.token, mFocusGrantToken,
-                            attrs.getTitle().toString(), outInputChannel);
+                            attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token,
+                            mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
                 }
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to grant input to surface: ", e);
@@ -381,16 +382,19 @@
             outMergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
         }
 
-        if ((attrChanges & WindowManager.LayoutParams.FLAGS_CHANGED) != 0
-                && state.mInputChannelToken != null) {
+        final int inputChangeMask = WindowManager.LayoutParams.FLAGS_CHANGED
+                | WindowManager.LayoutParams.INPUT_FEATURES_CHANGED;
+        if ((attrChanges & inputChangeMask) != 0 && state.mInputChannelToken != null) {
             try {
-                if(mRealWm instanceof IWindowSession.Stub) {
+                if (mRealWm instanceof IWindowSession.Stub) {
                     mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
                             new SurfaceControl(sc, "WindowlessWindowManager.relayout"),
-                            attrs.flags, attrs.privateFlags, state.mInputRegion);
+                            attrs.flags, attrs.privateFlags, attrs.inputFeatures,
+                            state.mInputRegion);
                 } else {
                     mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc,
-                            attrs.flags, attrs.privateFlags, state.mInputRegion);
+                            attrs.flags, attrs.privateFlags, attrs.inputFeatures,
+                            state.mInputRegion);
                 }
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to update surface input channel: ", e);
@@ -560,14 +564,14 @@
 
     @Override
     public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window,
-            IBinder hostInputToken, int flags, int privateFlags, int type,
+            IBinder hostInputToken, int flags, int privateFlags, int inputFeatures, int type,
             IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
             InputChannel outInputChannel) {
     }
 
     @Override
     public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
-            int flags, int privateFlags, Region region) {
+            int flags, int privateFlags, int inputFeatures, Region region) {
     }
 
     @Override
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2ed1817..220a193 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -720,14 +720,13 @@
          display is powered on at the same time. -->
     <bool name="config_supportsConcurrentInternalDisplays">true</bool>
 
-    <!-- Map of DeviceState to rotation lock setting. Each entry must be in the format
-         "key:value", for example: "0:1".
-          The keys are device states, and the values are one of
-          Settings.Secure.DeviceStateRotationLockSetting.
-          Any device state that doesn't have a default set here will be treated as
-          DEVICE_STATE_ROTATION_LOCK_IGNORED meaning it will not have its own rotation lock setting.
-          If this map is missing, the feature is disabled and only one global rotation lock setting
-           will apply, regardless of device state. -->
+    <!-- Map of device posture to rotation lock setting. Each entry must be in the format
+         "key:value", or "key:value:fallback_key" for example: "0:1" or "2:0:1". The keys are one of
+         Settings.Secure.DeviceStateRotationLockKey, and the values are one of
+         Settings.Secure.DeviceStateRotationLockSetting.
+         The fallback is a key to a device posture that can be specified when the value is
+         Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED.
+     -->
     <string-array name="config_perDeviceStateRotationLockDefaults" />
 
     <!-- Dock behavior -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index e5a4362..9ccd6eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -229,6 +229,7 @@
                     options.setLaunchedFromBubble(true);
                     options.setPendingIntentBackgroundActivityStartMode(
                             MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+                    options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
 
                     Intent fillInIntent = new Intent();
                     // Apply flags to make behaviour match documentLaunchMode=always.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 0a9c331..8cb575c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -103,6 +103,7 @@
                     null /* hostInputToken */,
                     FLAG_NOT_FOCUSABLE,
                     PRIVATE_FLAG_TRUSTED_OVERLAY,
+                    0 /* inputFeatures */,
                     TYPE_APPLICATION,
                     null /* windowToken */,
                     mFocusGrantToken,
@@ -208,6 +209,7 @@
                     mDecorationSurface,
                     FLAG_NOT_FOCUSABLE,
                     PRIVATE_FLAG_TRUSTED_OVERLAY,
+                    0 /* inputFeatures */,
                     touchRegion);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
diff --git a/packages/SettingsLib/DeviceStateRotationLock/Android.bp b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
index c642bd1..103309a 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/Android.bp
+++ b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
@@ -10,7 +10,10 @@
 android_library {
     name: "SettingsLibDeviceStateRotationLock",
 
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
 
     min_sdk_version: "21",
 }
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
index 10b004e..76e1df1 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
@@ -57,17 +57,19 @@
     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
     private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
     private final SecureSettings mSecureSettings;
-    private String[] mDeviceStateRotationLockDefaults;
-    private SparseIntArray mDeviceStateRotationLockSettings;
-    private SparseIntArray mDeviceStateDefaultRotationLockSettings;
-    private SparseIntArray mDeviceStateRotationLockFallbackSettings;
+    private final PosturesHelper mPosturesHelper;
+    private String[] mPostureRotationLockDefaults;
+    private SparseIntArray mPostureRotationLockSettings;
+    private SparseIntArray mPostureDefaultRotationLockSettings;
+    private SparseIntArray mPostureRotationLockFallbackSettings;
     private String mLastSettingValue;
     private List<SettableDeviceState> mSettableDeviceStates;
 
     @VisibleForTesting
     DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) {
-        this.mSecureSettings = secureSettings;
-        mDeviceStateRotationLockDefaults =
+        mSecureSettings = secureSettings;
+        mPosturesHelper = new PosturesHelper(context);
+        mPostureRotationLockDefaults =
                 context.getResources()
                         .getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
         loadDefaults();
@@ -134,13 +136,14 @@
 
     /** Updates the rotation lock setting for a specified device state. */
     public void updateSetting(int deviceState, boolean rotationLocked) {
-        if (mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState) >= 0) {
-            // The setting for this device state is IGNORED, and has a fallback device state.
-            // The setting for that fallback device state should be the changed in this case.
-            deviceState = mDeviceStateRotationLockFallbackSettings.get(deviceState);
+        int posture = mPosturesHelper.deviceStateToPosture(deviceState);
+        if (mPostureRotationLockFallbackSettings.indexOfKey(posture) >= 0) {
+            // The setting for this device posture is IGNORED, and has a fallback posture.
+            // The setting for that fallback posture should be the changed in this case.
+            posture = mPostureRotationLockFallbackSettings.get(posture);
         }
-        mDeviceStateRotationLockSettings.put(
-                deviceState,
+        mPostureRotationLockSettings.put(
+                posture,
                 rotationLocked
                         ? DEVICE_STATE_ROTATION_LOCK_LOCKED
                         : DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
@@ -159,22 +162,23 @@
      */
     @Settings.Secure.DeviceStateRotationLockSetting
     public int getRotationLockSetting(int deviceState) {
-        int rotationLockSetting = mDeviceStateRotationLockSettings.get(
-                deviceState, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
+        int devicePosture = mPosturesHelper.deviceStateToPosture(deviceState);
+        int rotationLockSetting = mPostureRotationLockSettings.get(
+                devicePosture, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
         if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
-            rotationLockSetting = getFallbackRotationLockSetting(deviceState);
+            rotationLockSetting = getFallbackRotationLockSetting(devicePosture);
         }
         return rotationLockSetting;
     }
 
-    private int getFallbackRotationLockSetting(int deviceState) {
-        int indexOfFallbackState = mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState);
-        if (indexOfFallbackState < 0) {
+    private int getFallbackRotationLockSetting(int devicePosture) {
+        int indexOfFallback = mPostureRotationLockFallbackSettings.indexOfKey(devicePosture);
+        if (indexOfFallback < 0) {
             Log.w(TAG, "Setting is ignored, but no fallback was specified.");
             return DEVICE_STATE_ROTATION_LOCK_IGNORED;
         }
-        int fallbackState = mDeviceStateRotationLockFallbackSettings.valueAt(indexOfFallbackState);
-        return mDeviceStateRotationLockSettings.get(fallbackState,
+        int fallbackPosture = mPostureRotationLockFallbackSettings.valueAt(indexOfFallback);
+        return mPostureRotationLockSettings.get(fallbackPosture,
                 /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
     }
 
@@ -189,8 +193,8 @@
      * DEVICE_STATE_ROTATION_LOCK_UNLOCKED}.
      */
     public boolean isRotationLockedForAllStates() {
-        for (int i = 0; i < mDeviceStateRotationLockSettings.size(); i++) {
-            if (mDeviceStateRotationLockSettings.valueAt(i)
+        for (int i = 0; i < mPostureRotationLockSettings.size(); i++) {
+            if (mPostureRotationLockSettings.valueAt(i)
                     == DEVICE_STATE_ROTATION_LOCK_UNLOCKED) {
                 return false;
             }
@@ -221,7 +225,7 @@
             fallbackOnDefaults();
             return;
         }
-        mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
+        mPostureRotationLockSettings = new SparseIntArray(values.length / 2);
         int key;
         int value;
 
@@ -230,7 +234,7 @@
                 key = Integer.parseInt(values[i++]);
                 value = Integer.parseInt(values[i++]);
                 boolean isPersistedValueIgnored = value == DEVICE_STATE_ROTATION_LOCK_IGNORED;
-                boolean isDefaultValueIgnored = mDeviceStateDefaultRotationLockSettings.get(key)
+                boolean isDefaultValueIgnored = mPostureDefaultRotationLockSettings.get(key)
                         == DEVICE_STATE_ROTATION_LOCK_IGNORED;
                 if (isPersistedValueIgnored != isDefaultValueIgnored) {
                     Log.w(TAG, "Conflict for ignored device state " + key
@@ -238,7 +242,7 @@
                     fallbackOnDefaults();
                     return;
                 }
-                mDeviceStateRotationLockSettings.put(key, value);
+                mPostureRotationLockSettings.put(key, value);
             } catch (NumberFormatException e) {
                 Log.wtf(TAG, "Error deserializing one of the saved settings", e);
                 fallbackOnDefaults();
@@ -253,7 +257,7 @@
      */
     @VisibleForTesting
     public void resetStateForTesting(Resources resources) {
-        mDeviceStateRotationLockDefaults =
+        mPostureRotationLockDefaults =
                 resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
         fallbackOnDefaults();
     }
@@ -264,23 +268,23 @@
     }
 
     private void persistSettings() {
-        if (mDeviceStateRotationLockSettings.size() == 0) {
+        if (mPostureRotationLockSettings.size() == 0) {
             persistSettingIfChanged(/* newSettingValue= */ "");
             return;
         }
 
         StringBuilder stringBuilder = new StringBuilder();
         stringBuilder
-                .append(mDeviceStateRotationLockSettings.keyAt(0))
+                .append(mPostureRotationLockSettings.keyAt(0))
                 .append(SEPARATOR_REGEX)
-                .append(mDeviceStateRotationLockSettings.valueAt(0));
+                .append(mPostureRotationLockSettings.valueAt(0));
 
-        for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
+        for (int i = 1; i < mPostureRotationLockSettings.size(); i++) {
             stringBuilder
                     .append(SEPARATOR_REGEX)
-                    .append(mDeviceStateRotationLockSettings.keyAt(i))
+                    .append(mPostureRotationLockSettings.keyAt(i))
                     .append(SEPARATOR_REGEX)
-                    .append(mDeviceStateRotationLockSettings.valueAt(i));
+                    .append(mPostureRotationLockSettings.valueAt(i));
         }
         persistSettingIfChanged(stringBuilder.toString());
     }
@@ -300,22 +304,20 @@
     }
 
     private void loadDefaults() {
-        mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
-        mDeviceStateDefaultRotationLockSettings = new SparseIntArray(
-                mDeviceStateRotationLockDefaults.length);
-        mDeviceStateRotationLockSettings = new SparseIntArray(
-                mDeviceStateRotationLockDefaults.length);
-        mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
-        for (String entry : mDeviceStateRotationLockDefaults) {
+        mSettableDeviceStates = new ArrayList<>(mPostureRotationLockDefaults.length);
+        mPostureDefaultRotationLockSettings = new SparseIntArray(
+                mPostureRotationLockDefaults.length);
+        mPostureRotationLockSettings = new SparseIntArray(mPostureRotationLockDefaults.length);
+        mPostureRotationLockFallbackSettings = new SparseIntArray(1);
+        for (String entry : mPostureRotationLockDefaults) {
             String[] values = entry.split(SEPARATOR_REGEX);
             try {
-                int deviceState = Integer.parseInt(values[0]);
+                int posture = Integer.parseInt(values[0]);
                 int rotationLockSetting = Integer.parseInt(values[1]);
                 if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
                     if (values.length == 3) {
-                        int fallbackDeviceState = Integer.parseInt(values[2]);
-                        mDeviceStateRotationLockFallbackSettings.put(deviceState,
-                                fallbackDeviceState);
+                        int fallbackPosture = Integer.parseInt(values[2]);
+                        mPostureRotationLockFallbackSettings.put(posture, fallbackPosture);
                     } else {
                         Log.w(TAG,
                                 "Rotation lock setting is IGNORED, but values have unexpected "
@@ -324,9 +326,14 @@
                     }
                 }
                 boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
-                mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
-                mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
-                mDeviceStateDefaultRotationLockSettings.put(deviceState, rotationLockSetting);
+                Integer deviceState = mPosturesHelper.postureToDeviceState(posture);
+                if (deviceState != null) {
+                    mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
+                } else {
+                    Log.wtf(TAG, "No matching device state for posture: " + posture);
+                }
+                mPostureRotationLockSettings.put(posture, rotationLockSetting);
+                mPostureDefaultRotationLockSettings.put(posture, rotationLockSetting);
             } catch (NumberFormatException e) {
                 Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
                 return;
@@ -338,13 +345,11 @@
     public void dump(IndentingPrintWriter pw) {
         pw.println("DeviceStateRotationLockSettingsManager");
         pw.increaseIndent();
-        pw.println("mDeviceStateRotationLockDefaults: " + Arrays.toString(
-                mDeviceStateRotationLockDefaults));
-        pw.println("mDeviceStateDefaultRotationLockSettings: "
-                + mDeviceStateDefaultRotationLockSettings);
-        pw.println("mDeviceStateRotationLockSettings: " + mDeviceStateRotationLockSettings);
-        pw.println("mDeviceStateRotationLockFallbackSettings: "
-                + mDeviceStateRotationLockFallbackSettings);
+        pw.println("mPostureRotationLockDefaults: "
+                + Arrays.toString(mPostureRotationLockDefaults));
+        pw.println("mPostureDefaultRotationLockSettings: " + mPostureDefaultRotationLockSettings);
+        pw.println("mDeviceStateRotationLockSettings: " + mPostureRotationLockSettings);
+        pw.println("mPostureRotationLockFallbackSettings: " + mPostureRotationLockFallbackSettings);
         pw.println("mSettableDeviceStates: " + mSettableDeviceStates);
         pw.println("mLastSettingValue: " + mLastSettingValue);
         pw.decreaseIndent();
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
new file mode 100644
index 0000000..9c70be9
--- /dev/null
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.settingslib.devicestate
+
+import android.content.Context
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN
+import android.provider.Settings.Secure.DeviceStateRotationLockKey
+import com.android.internal.R
+
+/** Helps to convert between device state and posture. */
+class PosturesHelper(context: Context) {
+
+    private val foldedDeviceStates =
+        context.resources.getIntArray(R.array.config_foldedDeviceStates)
+    private val halfFoldedDeviceStates =
+        context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
+    private val unfoldedDeviceStates =
+        context.resources.getIntArray(R.array.config_openDeviceStates)
+
+    @DeviceStateRotationLockKey
+    fun deviceStateToPosture(deviceState: Int): Int {
+        return when (deviceState) {
+            in foldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_FOLDED
+            in halfFoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+            in unfoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_UNFOLDED
+            else -> DEVICE_STATE_ROTATION_KEY_UNKNOWN
+        }
+    }
+
+    fun postureToDeviceState(@DeviceStateRotationLockKey posture: Int): Int? {
+        return when (posture) {
+            DEVICE_STATE_ROTATION_KEY_FOLDED -> foldedDeviceStates.firstOrNull()
+            DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> halfFoldedDeviceStates.firstOrNull()
+            DEVICE_STATE_ROTATION_KEY_UNFOLDED -> unfoldedDeviceStates.firstOrNull()
+            else -> null
+        }
+    }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
index 0fa15eb..fdefcde 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -70,12 +70,20 @@
         when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
+        when(mMockResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults))
+                .thenReturn(new String[]{"0:1", "1:0:2", "2:2"});
+        when(mMockResources.getIntArray(R.array.config_foldedDeviceStates))
+                .thenReturn(new int[]{0});
+        when(mMockResources.getIntArray(R.array.config_halfFoldedDeviceStates))
+                .thenReturn(new int[]{1});
+        when(mMockResources.getIntArray(R.array.config_openDeviceStates))
+                .thenReturn(new int[]{2});
         mFakeSecureSettings.registerContentObserver(
                 Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
                 /* notifyForDescendents= */ false, //NOTYPO
                 mContentObserver,
                 UserHandle.USER_CURRENT);
-        mManager = new DeviceStateRotationLockSettingsManager(context, mFakeSecureSettings);
+        mManager = new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
     }
 
     @Test
@@ -109,7 +117,7 @@
     public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
         when(mMockResources.getStringArray(
                 R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
-                new String[]{"2:2", "4:0", "1:1", "0:0"});
+                new String[]{"2:1", "1:0:1", "0:2"});
 
         List<SettableDeviceState> settableDeviceStates =
                 DeviceStateRotationLockSettingsManager.getInstance(
@@ -117,9 +125,8 @@
 
         assertThat(settableDeviceStates).containsExactly(
                 new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
-                new SettableDeviceState(/* deviceState= */ 4, /* isSettable= */ false),
-                new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ true),
-                new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
+                new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ false),
+                new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ true)
         ).inOrder();
     }
 
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 9b2f0ac..79948da 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -311,7 +311,7 @@
                     android:clickable="false"
                     android:focusable="false"
                     android:ellipsize="end"
-                    android:maxLines="3"
+                    android:maxLines="4"
                     android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
             </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
 
@@ -364,7 +364,7 @@
                     android:clickable="false"
                     android:focusable="false"
                     android:ellipsize="end"
-                    android:maxLines="3"
+                    android:maxLines="4"
                     android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
             </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ebf0f8e..2aa912c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2877,7 +2877,7 @@
     <string name="manage_users">Manage users</string>
 
     <!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
-    <string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string>
+    <string name="drag_split_not_supported">This notification does not support dragging to split screen</string>
 
     <!-- Content description for the Wi-Fi off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
     <string name="dream_overlay_status_bar_wifi_off">Wi\u2011Fi unavailable</string>
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index c0e1133..a80d28d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -236,12 +236,21 @@
 
     // TODO(b/270223352): Tracking Bug
     @JvmField
-    val HIDE_SMARTSPACE_ON_DREAM_OVERLAY = unreleasedFlag(404, "hide_smartspace_on_dream_overlay")
+    val HIDE_SMARTSPACE_ON_DREAM_OVERLAY =
+        unreleasedFlag(
+            404,
+            "hide_smartspace_on_dream_overlay",
+            teamfood = true
+    )
 
     // TODO(b/271460958): Tracking Bug
     @JvmField
-    val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY = unreleasedFlag(405,
-        "show_weather_complication_on_dream_overlay")
+    val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY =
+        unreleasedFlag(
+            405,
+            "show_weather_complication_on_dream_overlay",
+            teamfood = true
+        )
 
     // 500 - quick settings
 
@@ -661,8 +670,7 @@
 
     // 2600 - keyboard
     // TODO(b/259352579): Tracking Bug
-    @JvmField val SHORTCUT_LIST_SEARCH_LAYOUT =
-            unreleasedFlag(2600, "shortcut_list_search_layout", teamfood = true)
+    @JvmField val SHORTCUT_LIST_SEARCH_LAYOUT = releasedFlag(2600, "shortcut_list_search_layout")
 
     // TODO(b/259428678): Tracking Bug
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index a71e6dd..9ece72d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -26,6 +26,7 @@
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.util.leak.GarbageMonitor;
 
 import java.util.ArrayList;
@@ -33,7 +34,7 @@
 import java.util.Collection;
 import java.util.List;
 
-public interface QSHost {
+public interface QSHost extends PanelInteractor {
     String TILES_SETTING = Settings.Secure.QS_TILES;
     int POSITION_AT_END = -1;
 
@@ -57,9 +58,6 @@
     }
 
     void warn(String message, Throwable t);
-    void collapsePanels();
-    void forceCollapsePanels();
-    void openPanels();
     Context getContext();
     Context getUserContext();
     int getUserId();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt
new file mode 100644
index 0000000..958fa71
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.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.systemui.qs.dagger
+
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractorImpl
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+
+@Module
+interface QSHostModule {
+
+    @Binds fun provideQsHost(controllerImpl: QSTileHost): QSHost
+
+    @Module
+    companion object {
+        @Provides
+        @JvmStatic
+        fun providePanelInteractor(
+            featureFlags: FeatureFlags,
+            qsHost: QSHost,
+            panelInteractorImpl: PanelInteractorImpl
+        ): PanelInteractor {
+            return if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
+                panelInteractorImpl
+            } else {
+                qsHost
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 431d6e8..cfe9313 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -27,7 +27,6 @@
 import com.android.systemui.media.dagger.MediaModule;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.external.QSExternalModule;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -45,7 +44,6 @@
 
 import javax.inject.Named;
 
-import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 import dagger.multibindings.Multibinds;
@@ -54,7 +52,13 @@
  * Module for QS dependencies
  */
 @Module(subcomponents = {QSFragmentComponent.class},
-        includes = {MediaModule.class, QSExternalModule.class, QSFlagsModule.class})
+        includes = {
+                MediaModule.class,
+                QSExternalModule.class,
+                QSFlagsModule.class,
+                QSHostModule.class
+        }
+)
 public interface QSModule {
 
     /** A map of internal QS tiles. Ensures that this can be injected even if
@@ -100,8 +104,4 @@
         manager.init();
         return manager;
     }
-
-    /** */
-    @Binds
-    QSHost provideQsHost(QSTileHost controllerImpl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index adc7165..2083cc7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -40,6 +40,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -74,6 +75,7 @@
     private final CommandQueue mCommandQueue;
     private final UserTracker mUserTracker;
     private final StatusBarIconController mStatusBarIconController;
+    private final PanelInteractor mPanelInteractor;
 
     private int mMaxBound = DEFAULT_MAX_BOUND;
 
@@ -85,7 +87,8 @@
             UserTracker userTracker,
             KeyguardStateController keyguardStateController,
             CommandQueue commandQueue,
-            StatusBarIconController statusBarIconController) {
+            StatusBarIconController statusBarIconController,
+            PanelInteractor panelInteractor) {
         mHost = host;
         mKeyguardStateController = keyguardStateController;
         mContext = mHost.getContext();
@@ -96,6 +99,7 @@
         mCommandQueue = commandQueue;
         mStatusBarIconController = statusBarIconController;
         mCommandQueue.addCallback(mRequestListeningCallback);
+        mPanelInteractor = panelInteractor;
     }
 
     public Context getContext() {
@@ -255,7 +259,7 @@
         if (customTile != null) {
             verifyCaller(customTile);
             customTile.onDialogShown();
-            mHost.forceCollapsePanels();
+            mPanelInteractor.forceCollapsePanels();
             Objects.requireNonNull(mServices.get(customTile)).setShowingDialog(true);
         }
     }
@@ -275,7 +279,7 @@
         CustomTile customTile = getTileForToken(token);
         if (customTile != null) {
             verifyCaller(customTile);
-            mHost.forceCollapsePanels();
+            mPanelInteractor.forceCollapsePanels();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractor.kt
new file mode 100644
index 0000000..260caa7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.pipeline.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import java.util.Optional
+import javax.inject.Inject
+
+/** Encapsulates business logic for interacting with the QS panel. */
+interface PanelInteractor {
+
+    /** Collapse the shade */
+    fun collapsePanels()
+
+    /** Collapse the shade forcefully, skipping some animations. */
+    fun forceCollapsePanels()
+
+    /** Open the Quick Settings panel */
+    fun openPanels()
+}
+
+@SysUISingleton
+class PanelInteractorImpl
+@Inject
+constructor(
+    private val centralSurfaces: Optional<CentralSurfaces>,
+) : PanelInteractor {
+    override fun collapsePanels() {
+        centralSurfaces.ifPresent { it.postAnimateCollapsePanels() }
+    }
+
+    override fun forceCollapsePanels() {
+        centralSurfaces.ifPresent { it.postAnimateForceCollapsePanels() }
+    }
+
+    override fun openPanels() {
+        centralSurfaces.ifPresent { it.postAnimateOpenPanels() }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 89d402a3..27f5826 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -38,6 +38,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -52,6 +53,7 @@
 
     private final LocationController mController;
     private final KeyguardStateController mKeyguard;
+    private final PanelInteractor mPanelInteractor;
     private final Callback mCallback = new Callback();
 
     @Inject
@@ -65,12 +67,14 @@
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             LocationController locationController,
-            KeyguardStateController keyguardStateController
+            KeyguardStateController keyguardStateController,
+            PanelInteractor panelInteractor
     ) {
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
         mController = locationController;
         mKeyguard = keyguardStateController;
+        mPanelInteractor = panelInteractor;
         mController.observe(this, mCallback);
         mKeyguard.observe(this, mCallback);
     }
@@ -90,7 +94,7 @@
         if (mKeyguard.isMethodSecure() && mKeyguard.isShowing()) {
             mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
                 final boolean wasEnabled = mState.value;
-                mHost.openPanels();
+                mPanelInteractor.openPanels();
                 mController.setLocationEnabled(!wasEnabled);
             });
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 07b50c9..65592a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -42,6 +42,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -66,6 +67,7 @@
     private final Callback mCallback = new Callback();
     private final DialogLaunchAnimator mDialogLaunchAnimator;
     private final FeatureFlags mFlags;
+    private final PanelInteractor mPanelInteractor;
 
     private long mMillisUntilFinished = 0;
 
@@ -83,7 +85,8 @@
             RecordingController controller,
             KeyguardDismissUtil keyguardDismissUtil,
             KeyguardStateController keyguardStateController,
-            DialogLaunchAnimator dialogLaunchAnimator
+            DialogLaunchAnimator dialogLaunchAnimator,
+            PanelInteractor panelInteractor
     ) {
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
@@ -93,6 +96,7 @@
         mKeyguardDismissUtil = keyguardDismissUtil;
         mKeyguardStateController = keyguardStateController;
         mDialogLaunchAnimator = dialogLaunchAnimator;
+        mPanelInteractor = panelInteractor;
     }
 
     @Override
@@ -171,7 +175,7 @@
             // disable the exit animation which looks weird when it happens at the same time as the
             // shade collapsing.
             mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
-            getHost().collapsePanels();
+            mPanelInteractor.collapsePanels();
         };
 
         final Dialog dialog = mController.createScreenRecordDialog(mContext, mFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 33cbf06..a529da5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -68,6 +68,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.CallLayout;
@@ -1671,7 +1672,8 @@
             MetricsLogger metricsLogger,
             SmartReplyConstants smartReplyConstants,
             SmartReplyController smartReplyController,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            IStatusBarService statusBarService) {
         mEntry = entry;
         mAppName = appName;
         if (mMenuRow == null) {
@@ -1699,7 +1701,8 @@
                     mPeopleNotificationIdentifier,
                     rivSubcomponentFactory,
                     smartReplyConstants,
-                    smartReplyController);
+                    smartReplyController,
+                    statusBarService);
         }
         mOnUserInteractionCallback = onUserInteractionCallback;
         mBubblesManagerOptional = bubblesManagerOptional;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index e2a3111..5ca0866 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -29,6 +29,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -100,6 +101,7 @@
     private final SmartReplyController mSmartReplyController;
     private final ExpandableNotificationRowDragController mDragController;
     private final NotificationDismissibilityProvider mDismissibilityProvider;
+    private final IStatusBarService mStatusBarService;
     private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback =
             new ExpandableNotificationRow.ExpandableNotificationRowLogger() {
                 @Override
@@ -157,7 +159,8 @@
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             Optional<BubblesManager> bubblesManagerOptional,
             ExpandableNotificationRowDragController dragController,
-            NotificationDismissibilityProvider dismissibilityProvider) {
+            NotificationDismissibilityProvider dismissibilityProvider,
+            IStatusBarService statusBarService) {
         mView = view;
         mListContainer = listContainer;
         mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
@@ -189,6 +192,7 @@
         mSmartReplyConstants = smartReplyConstants;
         mSmartReplyController = smartReplyController;
         mDismissibilityProvider = dismissibilityProvider;
+        mStatusBarService = statusBarService;
     }
 
     /**
@@ -220,7 +224,8 @@
                 mMetricsLogger,
                 mSmartReplyConstants,
                 mSmartReplyController,
-                mFeatureFlags
+                mFeatureFlags,
+                mStatusBarService
         );
         mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
         if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 5834dcb..78392f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -21,10 +21,13 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.RemoteException;
 import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.IndentingPrintWriter;
@@ -39,6 +42,7 @@
 import android.widget.LinearLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.RemoteInputController;
@@ -129,6 +133,7 @@
     private Runnable mExpandedVisibleListener;
     private PeopleNotificationIdentifier mPeopleIdentifier;
     private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory;
+    private IStatusBarService mStatusBarService;
 
     /**
      * List of listeners for when content views become inactive (i.e. not the showing view).
@@ -196,11 +201,13 @@
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
             SmartReplyConstants smartReplyConstants,
-            SmartReplyController smartReplyController) {
+            SmartReplyController smartReplyController,
+            IStatusBarService statusBarService) {
         mPeopleIdentifier = peopleNotificationIdentifier;
         mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
         mSmartReplyConstants = smartReplyConstants;
         mSmartReplyController = smartReplyController;
+        mStatusBarService = statusBarService;
     }
 
     public void reinflate() {
@@ -2193,4 +2200,36 @@
     protected void setHeadsUpWrapper(NotificationViewWrapper headsUpWrapper) {
         mHeadsUpWrapper = headsUpWrapper;
     }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        try {
+            super.dispatchDraw(canvas);
+        } catch (Exception e) {
+            // Catch draw exceptions that may be caused by RemoteViews
+            Log.e(TAG, "Drawing view failed: " + e);
+            cancelNotification(e);
+        }
+    }
+
+    private void cancelNotification(Exception exception) {
+        try {
+            setVisibility(GONE);
+            final StatusBarNotification sbn = mNotificationEntry.getSbn();
+            if (mStatusBarService != null) {
+                // report notification inflation errors back up
+                // to notification delegates
+                mStatusBarService.onNotificationError(
+                        sbn.getPackageName(),
+                        sbn.getTag(),
+                        sbn.getId(),
+                        sbn.getUid(),
+                        sbn.getInitialPid(),
+                        exception.getMessage(),
+                        sbn.getUser().getIdentifier());
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "cancelNotification failed: " + ex);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 0bded73..46603df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -809,6 +809,11 @@
 
     public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) {
         mOccludeAnimationPlaying = occludeAnimationPlaying;
+
+        for (ScrimState state : ScrimState.values()) {
+            state.setOccludeAnimationPlaying(occludeAnimationPlaying);
+        }
+
         applyAndDispatchState();
     }
 
@@ -853,7 +858,6 @@
         if (mState == ScrimState.UNLOCKED || mState == ScrimState.DREAMING) {
             final boolean occluding =
                     mOccludeAnimationPlaying || mState.mLaunchingAffordanceWithPreview;
-
             // Darken scrim as it's pulled down while unlocked. If we're unlocked but playing the
             // screen off/occlusion animations, ignore expansion changes while those animations
             // play.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 0e9d3ce..7b20283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -243,7 +243,12 @@
                     : CentralSurfaces.FADE_KEYGUARD_DURATION;
 
             boolean fromAod = previousState == AOD || previousState == PULSING;
-            mAnimateChange = !mLaunchingAffordanceWithPreview && !fromAod;
+            // If launch/occlude animations were playing, they already animated the scrim
+            // alpha to 0f as part of the animation. If we animate it now, we'll set it back
+            // to 1f and animate it back to 0f, causing an unwanted scrim flash.
+            mAnimateChange = !mLaunchingAffordanceWithPreview
+                    && !mOccludeAnimationPlaying
+                    && !fromAod;
 
             mFrontTint = Color.TRANSPARENT;
             mBehindTint = Color.BLACK;
@@ -308,6 +313,7 @@
     boolean mWallpaperSupportsAmbientMode;
     boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
+    boolean mOccludeAnimationPlaying;
     boolean mWakeLockScreenSensorActive;
     boolean mKeyguardFadingAway;
     long mKeyguardFadingAwayDuration;
@@ -411,6 +417,10 @@
         mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview;
     }
 
+    public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) {
+        mOccludeAnimationPlaying = occludeAnimationPlaying;
+    }
+
     public boolean isLowPowerState() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index a0a0372..209ea41 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -59,6 +59,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.MessageRouter;
@@ -412,6 +413,7 @@
         private final GarbageMonitor gm;
         private ProcessMemInfo pmi;
         private boolean dumpInProgress;
+        private final PanelInteractor mPanelInteractor;
 
         @Inject
         public MemoryTile(
@@ -423,11 +425,13 @@
                 StatusBarStateController statusBarStateController,
                 ActivityStarter activityStarter,
                 QSLogger qsLogger,
-                GarbageMonitor monitor
+                GarbageMonitor monitor,
+                PanelInteractor panelInteractor
         ) {
             super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                     statusBarStateController, activityStarter, qsLogger);
             gm = monitor;
+            mPanelInteractor = panelInteractor;
         }
 
         @Override
@@ -457,7 +461,7 @@
                     mHandler.post(() -> {
                         dumpInProgress = false;
                         refreshState();
-                        getHost().collapsePanels();
+                        mPanelInteractor.collapsePanels();
                         mActivityStarter.postStartActivityDismissingKeyguard(shareIntent, 0);
                     });
                 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 64e9a3e..7e052bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -29,6 +29,7 @@
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -41,6 +42,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -91,6 +93,8 @@
     private TileLifecycleManager mTileLifecycleManager;
     @Mock
     private QSHost mQSHost;
+    @Mock
+    private PanelInteractor mPanelInteractor;
 
     @Before
     public void setUp() throws Exception {
@@ -107,7 +111,8 @@
         Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper());
 
         mTileService = new TestTileServices(mQSHost, provider, mBroadcastDispatcher,
-                mUserTracker, mKeyguardStateController, mCommandQueue, mStatusBarIconController);
+                mUserTracker, mKeyguardStateController, mCommandQueue, mStatusBarIconController,
+                mPanelInteractor);
     }
 
     @After
@@ -222,13 +227,37 @@
         verify(tile, never()).startActivityAndCollapse(pi);
     }
 
+    @Test
+    public void testOnStartActivityCollapsesPanel() {
+        CustomTile tile = mock(CustomTile.class);
+        ComponentName componentName = mock(ComponentName.class);
+        when(tile.getComponent()).thenReturn(componentName);
+        when(componentName.getPackageName()).thenReturn(this.getContext().getPackageName());
+        TileServiceManager manager = mTileService.getTileWrapper(tile);
+
+        mTileService.onStartActivity(manager.getToken());
+        verify(mPanelInteractor).forceCollapsePanels();
+    }
+
+    @Test
+    public void testOnShowDialogCollapsesPanel() {
+        CustomTile tile = mock(CustomTile.class);
+        ComponentName componentName = mock(ComponentName.class);
+        when(tile.getComponent()).thenReturn(componentName);
+        when(componentName.getPackageName()).thenReturn(this.getContext().getPackageName());
+        TileServiceManager manager = mTileService.getTileWrapper(tile);
+
+        mTileService.onShowDialog(manager.getToken());
+        verify(mPanelInteractor).forceCollapsePanels();
+    }
+
     private class TestTileServices extends TileServices {
         TestTileServices(QSHost host, Provider<Handler> handlerProvider,
                 BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
                 KeyguardStateController keyguardStateController, CommandQueue commandQueue,
-                StatusBarIconController statusBarIconController) {
+                StatusBarIconController statusBarIconController, PanelInteractor panelInteractor) {
             super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController,
-                    commandQueue, statusBarIconController);
+                    commandQueue, statusBarIconController, panelInteractor);
         }
 
         @Override
@@ -237,6 +266,8 @@
             TileServiceManager manager = mock(TileServiceManager.class);
             mManagers.add(manager);
             when(manager.isLifecycleStarted()).thenReturn(true);
+            Binder b = new Binder();
+            when(manager.getToken()).thenReturn(b);
             return manager;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
new file mode 100644
index 0000000..45783ab
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.systemui.qs.pipeline.domain.interactor
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import java.util.Optional
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class PanelInteractorImplTest : SysuiTestCase() {
+
+    @Mock private lateinit var centralSurfaces: CentralSurfaces
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun openPanels_callsCentralSurfaces() {
+        val underTest = PanelInteractorImpl(Optional.of(centralSurfaces))
+
+        underTest.openPanels()
+
+        verify(centralSurfaces).postAnimateOpenPanels()
+    }
+
+    @Test
+    fun collapsePanels_callsCentralSurfaces() {
+        val underTest = PanelInteractorImpl(Optional.of(centralSurfaces))
+
+        underTest.collapsePanels()
+
+        verify(centralSurfaces).postAnimateCollapsePanels()
+    }
+
+    @Test
+    fun forceCollapsePanels_callsCentralSurfaces() {
+        val underTest = PanelInteractorImpl(Optional.of(centralSurfaces))
+
+        underTest.forceCollapsePanels()
+
+        verify(centralSurfaces).postAnimateForceCollapsePanels()
+    }
+
+    @Test
+    fun whenOptionalEmpty_doesnThrow() {
+        val underTest = PanelInteractorImpl(Optional.empty())
+
+        underTest.openPanels()
+        underTest.collapsePanels()
+        underTest.forceCollapsePanels()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
index 33921c7..3642e87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
@@ -31,9 +31,12 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.policy.LocationController
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
@@ -41,6 +44,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
@@ -65,6 +69,8 @@
     private lateinit var locationController: LocationController
     @Mock
     private lateinit var keyguardStateController: KeyguardStateController
+    @Mock
+    private lateinit var panelInteractor: PanelInteractor
 
     private val uiEventLogger = UiEventLoggerFake()
     private lateinit var testableLooper: TestableLooper
@@ -86,7 +92,9 @@
             activityStarter,
             qsLogger,
             locationController,
-            keyguardStateController)
+            keyguardStateController,
+            panelInteractor,
+        )
     }
 
     @After
@@ -116,4 +124,18 @@
         assertThat(state.icon)
             .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_location_icon_on))
     }
+
+    @Test
+    fun testClickWhenLockedWillCallOpenPanels() {
+        `when`(keyguardStateController.isMethodSecure).thenReturn(true)
+        `when`(keyguardStateController.isShowing).thenReturn(true)
+
+        tile.handleClick(null)
+
+        val captor = argumentCaptor<Runnable>()
+        verify(activityStarter).postQSRunnableDismissingKeyguard(capture(captor))
+        captor.value.run()
+
+        verify(panelInteractor).openPanels()
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 5aef758..d9ed1a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -83,6 +84,8 @@
     private KeyguardStateController mKeyguardStateController;
     @Mock
     private DialogLaunchAnimator mDialogLaunchAnimator;
+    @Mock
+    private PanelInteractor mPanelInteractor;
 
     private TestableLooper mTestableLooper;
     private ScreenRecordTile mTile;
@@ -108,7 +111,8 @@
                 mController,
                 mKeyguardDismissUtil,
                 mKeyguardStateController,
-                mDialogLaunchAnimator
+                mDialogLaunchAnimator,
+                mPanelInteractor
         );
 
         mTile.initialize();
@@ -146,7 +150,7 @@
         assertNotNull(onStartRecordingClicked.getValue());
         onStartRecordingClicked.getValue().run();
         verify(mDialogLaunchAnimator).disableAllCurrentDialogsExitAnimations();
-        verify(mHost).collapsePanels();
+        verify(mPanelInteractor).collapsePanels();
     }
 
     // Test that the tile is active and labeled correctly when the controller is starting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index c92134b..60bc3a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -21,6 +21,7 @@
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.MetricsLogger
+import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FeatureFlags
@@ -93,6 +94,7 @@
     private val bubblesManager: BubblesManager = mock()
     private val dragController: ExpandableNotificationRowDragController = mock()
     private val dismissibilityProvider: NotificationDismissibilityProvider = mock()
+    private val statusBarService: IStatusBarService = mock()
 
     private lateinit var controller: ExpandableNotificationRowController
 
@@ -130,7 +132,8 @@
                 peopleNotificationIdentifier,
                 Optional.of(bubblesManager),
                 dragController,
-                dismissibilityProvider
+                dismissibilityProvider,
+                statusBarService
             )
         whenever(view.childrenContainer).thenReturn(childrenContainer)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 7b2051d..0b90ebe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -74,7 +74,7 @@
         doReturn(10).whenever(spyRow).intrinsicHeight
 
         with(view) {
-            initialize(mPeopleNotificationIdentifier, mock(), mock(), mock())
+            initialize(mPeopleNotificationIdentifier, mock(), mock(), mock(), mock())
             setContainingNotification(spyRow)
             setHeights(/* smallHeight= */ 10, /* headsUpMaxHeight= */ 20, /* maxHeight= */ 30)
             contractedChild = createViewWithHeight(10)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index f8a8e50..813bae8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -49,6 +49,7 @@
 import android.widget.RemoteViews;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.TestableDependency;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
@@ -582,7 +583,8 @@
                 mock(MetricsLogger.class),
                 mock(SmartReplyConstants.class),
                 mock(SmartReplyController.class),
-                mFeatureFlags);
+                mFeatureFlags,
+                mock(IStatusBarService.class));
 
         row.setAboveShelfChangedListener(aboveShelf -> { });
         mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 7a1270f..a9ed175 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -25,6 +25,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -1163,8 +1164,8 @@
     @Test
     public void testScrimFocus() {
         mScrimController.transitionTo(ScrimState.AOD);
-        Assert.assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
-        Assert.assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
+        assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
+        assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
 
         mScrimController.transitionTo(ScrimState.KEYGUARD);
         Assert.assertTrue("Should be focusable on keyguard", mScrimBehind.isFocusable());
@@ -1224,7 +1225,7 @@
     public void testAnimatesTransitionToAod() {
         when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
         ScrimState.AOD.prepare(ScrimState.KEYGUARD);
-        Assert.assertFalse("No animation when ColorFade kicks in",
+        assertFalse("No animation when ColorFade kicks in",
                 ScrimState.AOD.getAnimateChange());
 
         reset(mDozeParameters);
@@ -1236,9 +1237,9 @@
 
     @Test
     public void testViewsDontHaveFocusHighlight() {
-        Assert.assertFalse("Scrim shouldn't have focus highlight",
+        assertFalse("Scrim shouldn't have focus highlight",
                 mScrimInFront.getDefaultFocusHighlightEnabled());
-        Assert.assertFalse("Scrim shouldn't have focus highlight",
+        assertFalse("Scrim shouldn't have focus highlight",
                 mScrimBehind.getDefaultFocusHighlightEnabled());
     }
 
@@ -1738,7 +1739,7 @@
     @Test
     public void aodStateSetsFrontScrimToNotBlend() {
         mScrimController.transitionTo(ScrimState.AOD);
-        Assert.assertFalse("Front scrim should not blend with main color",
+        assertFalse("Front scrim should not blend with main color",
                 mScrimInFront.shouldBlendWithMainColor());
     }
 
@@ -1773,6 +1774,14 @@
         verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
     }
 
+    @Test
+    public void testDoNotAnimateChangeIfOccludeAnimationPlaying() {
+        mScrimController.setOccludeAnimationPlaying(true);
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+
+        assertFalse(ScrimState.UNLOCKED.mAnimateChange);
+    }
+
     private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
         mScrimController.setRawPanelExpansionFraction(expansion);
         finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 481d453..c8f28bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -55,6 +55,9 @@
 public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
 
     private static final String[] DEFAULT_SETTINGS = new String[]{"0:1", "2:0:1", "1:2"};
+    private static final int[] DEFAULT_FOLDED_STATES = new int[]{0};
+    private static final int[] DEFAULT_HALF_FOLDED_STATES = new int[]{2};
+    private static final int[] DEFAULT_UNFOLDED_STATES = new int[]{1};
 
     @Mock private DeviceStateManager mDeviceStateManager;
     @Mock private DeviceStateRotationLockSettingControllerLogger mLogger;
@@ -73,6 +76,9 @@
         MockitoAnnotations.initMocks(/* testClass= */ this);
         TestableResources resources = mContext.getOrCreateTestableResources();
         resources.addOverride(R.array.config_perDeviceStateRotationLockDefaults, DEFAULT_SETTINGS);
+        resources.addOverride(R.array.config_foldedDeviceStates, DEFAULT_FOLDED_STATES);
+        resources.addOverride(R.array.config_halfFoldedDeviceStates, DEFAULT_HALF_FOLDED_STATES);
+        resources.addOverride(R.array.config_openDeviceStates, DEFAULT_UNFOLDED_STATES);
 
         ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor =
                 ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7550196..b4e75e1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9351,7 +9351,9 @@
 
                 String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
                 String maxBytesSetting = Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag;
-                int lines = Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0);
+                int lines = Build.IS_USER
+                        ? 0
+                        : Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0);
                 int dropboxMaxSize = Settings.Global.getInt(
                         mContext.getContentResolver(), maxBytesSetting, DROPBOX_DEFAULT_MAX_SIZE);
                 int maxDataFileSize = dropboxMaxSize - sb.length()
diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
index 77cd673..a081dff 100644
--- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
@@ -92,6 +92,8 @@
     // Represents an HAL interface version. Instances of this class are created in the JNI layer
     // and returned through native methods.
     static class HalInterfaceVersion {
+        // mMajor being this value denotes AIDL HAL. In this case, mMinor denotes the AIDL version.
+        static final int AIDL_INTERFACE = 3;
         final int mMajor;
         final int mMinor;
 
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 6c4c829..041f11d 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -21,6 +21,7 @@
 import static com.android.server.location.gnss.GnssManagerService.D;
 import static com.android.server.location.gnss.GnssManagerService.TAG;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.location.GnssMeasurementRequest;
@@ -31,6 +32,7 @@
 import android.stats.location.LocationStatsEnums;
 import android.util.Log;
 
+import com.android.server.location.gnss.GnssConfiguration.HalInterfaceVersion;
 import com.android.server.location.gnss.hal.GnssNative;
 import com.android.server.location.injector.AppOpsHelper;
 import com.android.server.location.injector.Injector;
@@ -115,16 +117,6 @@
         if (request.getIntervalMillis() == GnssMeasurementRequest.PASSIVE_INTERVAL) {
             return true;
         }
-        // The HAL doc does not specify if consecutive start() calls will be allowed.
-        // Some vendors may ignore the 2nd start() call if stop() is not called.
-        // Thus, here we always call stop() before calling start() to avoid being ignored.
-        if (mGnssNative.stopMeasurementCollection()) {
-            if (D) {
-                Log.d(TAG, "stopping gnss measurements");
-            }
-        } else {
-            Log.e(TAG, "error stopping gnss measurements");
-        }
         if (mGnssNative.startMeasurementCollection(request.isFullTracking(),
                 request.isCorrelationVectorOutputsEnabled(),
                 request.getIntervalMillis())) {
@@ -139,6 +131,28 @@
     }
 
     @Override
+    protected boolean reregisterWithService(GnssMeasurementRequest old,
+            GnssMeasurementRequest request,
+            @NonNull Collection<GnssListenerRegistration> registrations) {
+        if (request.getIntervalMillis() == GnssMeasurementRequest.PASSIVE_INTERVAL) {
+            unregisterWithService();
+            return true;
+        }
+        HalInterfaceVersion halInterfaceVersion =
+                mGnssNative.getConfiguration().getHalInterfaceVersion();
+        boolean aidlV3Plus = halInterfaceVersion.mMajor == HalInterfaceVersion.AIDL_INTERFACE
+                && halInterfaceVersion.mMinor >= 3;
+        if (!aidlV3Plus) {
+            // The HAL doc does not specify if consecutive start() calls will be allowed.
+            // Some vendors may ignore the 2nd start() call if stop() is not called.
+            // Thus, here we always call stop() before calling start() to avoid being ignored.
+            // AIDL v3+ is free from this issue.
+            unregisterWithService();
+        }
+        return registerWithService(request, registrations);
+    }
+
+    @Override
     protected void unregisterWithService() {
         if (mGnssNative.stopMeasurementCollection()) {
             if (D) {
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index d160740..5312ae6 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -69,7 +69,6 @@
 
         for (InstallRequest installRequest :  installRequests) {
             installRequest.onReconcileStarted();
-            final String installPackageName = installRequest.getParsedPackage().getPackageName();
 
             // add / replace existing with incoming packages
             combinedPackages.put(installRequest.getScannedPackageSetting().getPackageName(),
@@ -84,12 +83,17 @@
                             incomingSharedLibraries, info)) {
                         throw ReconcileFailure.ofInternalError(
                                 "Shared Library " + info.getName()
-                                + " is being installed twice in this set!",
+                                        + " is being installed twice in this set!",
                                 PackageManagerException.INTERNAL_ERROR_SHARED_LIB_INSTALLED_TWICE);
                     }
                 }
             }
+        }
 
+        for (InstallRequest installRequest : installRequests) {
+            final String installPackageName = installRequest.getParsedPackage().getPackageName();
+            final List<SharedLibraryInfo> allowedSharedLibInfos =
+                    sharedLibraries.getAllowedSharedLibInfos(installRequest);
 
             final DeletePackageAction deletePackageAction;
             // we only want to try to delete for non system apps
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b1ca72b..78ee6f9 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -857,7 +857,7 @@
     @Override
     public void grantInputChannel(int displayId, SurfaceControl surface,
             IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type,
-            IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
+            int inputFeatures, IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
             InputChannel outInputChannel) {
         if (hostInputToken == null && !mCanAddInternalSystemWindow) {
             // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
@@ -869,7 +869,7 @@
         try {
             mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken,
                     flags, mCanAddInternalSystemWindow ? privateFlags : 0,
-                    type, windowToken, focusGrantToken, inputHandleName,
+                    type, inputFeatures, windowToken, focusGrantToken, inputHandleName,
                     outInputChannel);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -878,11 +878,11 @@
 
     @Override
     public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
-            int flags, int privateFlags, Region region) {
+            int flags, int privateFlags, int inputFeatures, Region region) {
         final long identity = Binder.clearCallingIdentity();
         try {
             mService.updateInputChannel(channelToken, displayId, surface, flags,
-                    mCanAddInternalSystemWindow ? privateFlags : 0, region);
+                    mCanAddInternalSystemWindow ? privateFlags : 0, inputFeatures, region);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8582356..be42f36 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8571,8 +8571,8 @@
      */
     void grantInputChannel(Session session, int callingUid, int callingPid, int displayId,
             SurfaceControl surface, IWindow window, IBinder hostInputToken,
-            int flags, int privateFlags, int type, IBinder windowToken, IBinder focusGrantToken,
-            String inputHandleName, InputChannel outInputChannel) {
+            int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken,
+            IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) {
         final int sanitizedType = sanitizeWindowType(session, displayId, windowToken, type);
         final InputApplicationHandle applicationHandle;
         final String name;
@@ -8589,7 +8589,7 @@
         }
 
         updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
-                name, applicationHandle, flags, privateFlags, sanitizedType,
+                name, applicationHandle, flags, privateFlags, inputFeatures, sanitizedType,
                 null /* region */, window);
 
         clientChannel.copyTo(outInputChannel);
@@ -8630,13 +8630,14 @@
     private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
             int displayId, SurfaceControl surface, String name,
             InputApplicationHandle applicationHandle, int flags,
-            int privateFlags, int type, Region region, IWindow window) {
+            int privateFlags, int inputFeatures, int type, Region region, IWindow window) {
         final InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
         h.token = channelToken;
         h.setWindowToken(window);
         h.name = name;
 
         flags = sanitizeFlagSlippery(flags, name, callingUid, callingPid);
+        inputFeatures = sanitizeSpyWindow(inputFeatures, name, callingUid, callingPid);
 
         final int sanitizedLpFlags =
                 (flags & (FLAG_NOT_TOUCHABLE | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE))
@@ -8646,7 +8647,7 @@
 
         // Do not allow any input features to be set without sanitizing them first.
         h.inputConfig = InputConfigAdapter.getInputConfigFromWindowParams(
-                        type, sanitizedLpFlags, 0 /*inputFeatures*/);
+                        type, sanitizedLpFlags, inputFeatures);
 
 
         if ((flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0) {
@@ -8683,7 +8684,7 @@
      * is undefined.
      */
     void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
-            int flags, int privateFlags, Region region) {
+            int flags, int privateFlags, int inputFeatures, Region region) {
         final InputApplicationHandle applicationHandle;
         final String name;
         final EmbeddedWindowController.EmbeddedWindow win;
@@ -8698,7 +8699,8 @@
         }
 
         updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
-                applicationHandle, flags, privateFlags, win.mWindowType, region, win.mClient);
+                applicationHandle, flags, privateFlags, inputFeatures, win.mWindowType, region,
+                win.mClient);
     }
 
     /** Return whether layer tracing is enabled */
diff --git a/services/core/jni/gnss/GnssConfiguration.cpp b/services/core/jni/gnss/GnssConfiguration.cpp
index 3677641..b57e451 100644
--- a/services/core/jni/gnss/GnssConfiguration.cpp
+++ b/services/core/jni/gnss/GnssConfiguration.cpp
@@ -67,7 +67,7 @@
       : mIGnssConfiguration(iGnssConfiguration) {}
 
 jobject GnssConfiguration::getVersion(JNIEnv* env) {
-    return createHalInterfaceVersionJavaObject(env, 3, 0);
+    return createHalInterfaceVersionJavaObject(env, 3, mIGnssConfiguration->getInterfaceVersion());
 }
 
 jboolean GnssConfiguration::setEmergencySuplPdn(jint enable) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 720533f..321924c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21882,7 +21882,9 @@
                     }
                     if (!isProfileOwnerOfOrganizationOwnedDevice(
                             admin.info.getComponent(), user.getIdentifier())
-                            && !isDeviceOwner(admin)) {
+                            && !isDeviceOwner(admin)
+                            && !(isProfileOwner(admin.info.getComponent(), user.getIdentifier())
+                            && admin.getUserHandle().isSystem())) {
                         continue;
                     }
                     // Don't send the broadcast twice if the DPC is the same package as the
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
new file mode 100644
index 0000000..fd9dfe8
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+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.content.Context;
+import android.location.GnssMeasurementRequest;
+import android.location.IGnssMeasurementsListener;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.util.identity.CallerIdentity;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+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.FakeUserInfoHelper;
+import com.android.server.location.injector.Injector;
+import com.android.server.location.injector.TestInjector;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Objects;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GnssMeasurementsProviderTest {
+    private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+    private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1000,
+            "mypackage", "attribution", "listener");
+    private static final GnssConfiguration.HalInterfaceVersion HIDL_V2_1 =
+            new GnssConfiguration.HalInterfaceVersion(
+                    2, 1);
+    private static final GnssConfiguration.HalInterfaceVersion AIDL_V3 =
+            new GnssConfiguration.HalInterfaceVersion(
+                    GnssConfiguration.HalInterfaceVersion.AIDL_INTERFACE, 3);
+    private static final GnssMeasurementRequest ACTIVE_REQUEST =
+            new GnssMeasurementRequest.Builder().build();
+    private static final GnssMeasurementRequest PASSIVE_REQUEST =
+            new GnssMeasurementRequest.Builder().setIntervalMillis(
+                    GnssMeasurementRequest.PASSIVE_INTERVAL).build();
+    private @Mock Context mContext;
+    private @Mock LocationManagerInternal mInternal;
+    private @Mock GnssConfiguration mMockConfiguration;
+    private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
+    private @Mock IGnssMeasurementsListener mListener1;
+    private @Mock IGnssMeasurementsListener mListener2;
+    private @Mock IBinder mBinder1;
+    private @Mock IBinder mBinder2;
+
+    private GnssNative mGnssNative;
+
+    private GnssMeasurementsProvider mTestProvider;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        doReturn(mBinder1).when(mListener1).asBinder();
+        doReturn(mBinder2).when(mListener2).asBinder();
+        doReturn(true).when(mInternal).isProviderEnabledForUser(eq(LocationManager.GPS_PROVIDER),
+                anyInt());
+        LocalServices.addService(LocationManagerInternal.class, mInternal);
+        FakeGnssHal fakeGnssHal = new FakeGnssHal();
+        GnssNative.setGnssHalForTest(fakeGnssHal);
+        Injector injector = new TestInjector(mContext);
+        mGnssNative = spy(Objects.requireNonNull(
+                GnssNative.create(injector, mMockConfiguration)));
+        mGnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
+        mTestProvider = new GnssMeasurementsProvider(injector, mGnssNative);
+        mGnssNative.register();
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(LocationManagerInternal.class);
+    }
+
+    @Test
+    public void testAddListener_active() {
+        // add the active request
+        mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, times(1)).startMeasurementCollection(
+                eq(ACTIVE_REQUEST.isFullTracking()),
+                eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+                eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+        // remove the active request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+    }
+
+    @Test
+    public void testAddListener_passive() {
+        // add the passive request
+        mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+                anyInt());
+
+        // remove the passive request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+    }
+
+    @Test
+    public void testReregister_aidlV3Plus() {
+        doReturn(AIDL_V3).when(mMockConfiguration).getHalInterfaceVersion();
+
+        // add the passive request
+        mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+                anyInt());
+
+        // add the active request, reregister with the active request
+        mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener2);
+        verify(mGnssNative, never()).stopMeasurementCollection();
+        verify(mGnssNative, times(1)).startMeasurementCollection(
+                eq(ACTIVE_REQUEST.isFullTracking()),
+                eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+                eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+        // remove the active request, reregister with the passive request
+        mTestProvider.removeListener(mListener2);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+
+        // remove the passive request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(2)).stopMeasurementCollection();
+    }
+
+    @Test
+    public void testReregister_preAidlV3() {
+        doReturn(HIDL_V2_1).when(mMockConfiguration).getHalInterfaceVersion();
+
+        // add the passive request
+        mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+        verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+                anyInt());
+
+        // add the active request, reregister with the active request
+        mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener2);
+        verify(mGnssNative, times(1)).stopMeasurementCollection();
+        verify(mGnssNative, times(1)).startMeasurementCollection(
+                eq(ACTIVE_REQUEST.isFullTracking()),
+                eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+                eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+        // remove the active request, reregister with the passive request
+        mTestProvider.removeListener(mListener2);
+        verify(mGnssNative, times(2)).stopMeasurementCollection();
+
+        // remove the passive request
+        mTestProvider.removeListener(mListener1);
+        verify(mGnssNative, times(3)).stopMeasurementCollection();
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 7d6cf4a..677ec46 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -26,7 +26,10 @@
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_OWN_FOCUS;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -49,11 +52,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -67,12 +72,16 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.InputConfig;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
+import android.view.IWindow;
 import android.view.IWindowSessionCallback;
+import android.view.InputChannel;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.Surface;
@@ -690,6 +699,102 @@
         assertEquals(validRect, resultingArgs.mSourceCrop);
     }
 
+    @Test
+    public void testGrantInputChannel_sanitizeSpyWindowForApplications() {
+        final Session session = mock(Session.class);
+        final int callingUid = Process.FIRST_APPLICATION_UID;
+        final int callingPid = 1234;
+        final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+        final IWindow window = mock(IWindow.class);
+        final IBinder windowToken = mock(IBinder.class);
+        when(window.asBinder()).thenReturn(windowToken);
+        final IBinder focusGrantToken = mock(IBinder.class);
+
+        final InputChannel inputChannel = new InputChannel();
+        assertThrows(IllegalArgumentException.class, () ->
+                mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY,
+                        surfaceControl, window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE,
+                        PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, TYPE_APPLICATION,
+                        null /* windowToken */, focusGrantToken, "TestInputChannel",
+                        inputChannel));
+    }
+
+    @Test
+    public void testGrantInputChannel_allowSpyWindowForInputMonitorPermission() {
+        final Session session = mock(Session.class);
+        final int callingUid = Process.SYSTEM_UID;
+        final int callingPid = 1234;
+        final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+        final IWindow window = mock(IWindow.class);
+        final IBinder windowToken = mock(IBinder.class);
+        when(window.asBinder()).thenReturn(windowToken);
+        final IBinder focusGrantToken = mock(IBinder.class);
+
+        final InputChannel inputChannel = new InputChannel();
+        mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl,
+                window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY,
+                INPUT_FEATURE_SPY, TYPE_APPLICATION, null /* windowToken */, focusGrantToken,
+                "TestInputChannel", inputChannel);
+
+        verify(mTransaction).setInputWindowInfo(
+                eq(surfaceControl),
+                argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY));
+    }
+
+    @Test
+    public void testUpdateInputChannel_sanitizeSpyWindowForApplications() {
+        final Session session = mock(Session.class);
+        final int callingUid = Process.FIRST_APPLICATION_UID;
+        final int callingPid = 1234;
+        final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+        final IWindow window = mock(IWindow.class);
+        final IBinder windowToken = mock(IBinder.class);
+        when(window.asBinder()).thenReturn(windowToken);
+        final IBinder focusGrantToken = mock(IBinder.class);
+
+        final InputChannel inputChannel = new InputChannel();
+        mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl,
+                window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY,
+                0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken,
+                "TestInputChannel", inputChannel);
+        verify(mTransaction).setInputWindowInfo(
+                eq(surfaceControl),
+                argThat(h -> (h.inputConfig & InputConfig.SPY) == 0));
+
+        assertThrows(IllegalArgumentException.class, () ->
+                mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl,
+                        FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY,
+                        null /* region */));
+    }
+
+    @Test
+    public void testUpdateInputChannel_allowSpyWindowForInputMonitorPermission() {
+        final Session session = mock(Session.class);
+        final int callingUid = Process.SYSTEM_UID;
+        final int callingPid = 1234;
+        final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+        final IWindow window = mock(IWindow.class);
+        final IBinder windowToken = mock(IBinder.class);
+        when(window.asBinder()).thenReturn(windowToken);
+        final IBinder focusGrantToken = mock(IBinder.class);
+
+        final InputChannel inputChannel = new InputChannel();
+        mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl,
+                window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY,
+                0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken,
+                "TestInputChannel", inputChannel);
+        verify(mTransaction).setInputWindowInfo(
+                eq(surfaceControl),
+                argThat(h -> (h.inputConfig & InputConfig.SPY) == 0));
+
+        mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl,
+                FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY,
+                null /* region */);
+        verify(mTransaction).setInputWindowInfo(
+                eq(surfaceControl),
+                argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY));
+    }
+
     private void setupActivityWithLaunchCookie(IBinder launchCookie, WindowContainerToken wct) {
         final WindowContainer.RemoteToken remoteToken = mock(WindowContainer.RemoteToken.class);
         when(remoteToken.toWindowContainerToken()).thenReturn(wct);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 212dc41..7aa1334 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -8654,6 +8654,16 @@
         public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY =
                 KEY_PREFIX + "epdg_address_priority_int_array";
 
+        /**
+         * A priority list of PLMN to be used in EPDG_ADDRESS_PLMN. Possible values are {@link
+         * #EPDG_PLMN_RPLMN}, {@link #EPDG_PLMN_HPLMN}, {@link #EPDG_PLMN_EHPLMN_ALL}, {@link
+         * #EPDG_PLMN_EHPLMN_FIRST}
+         *
+         * @hide
+         */
+        public static final String KEY_EPDG_PLMN_PRIORITY_INT_ARRAY =
+                KEY_PREFIX + "epdg_plmn_priority_int_array";
+
         /** Epdg static IP address or FQDN */
         public static final String KEY_EPDG_STATIC_ADDRESS_STRING =
                 KEY_PREFIX + "epdg_static_address_string";
@@ -8854,6 +8864,36 @@
         public static final int EPDG_ADDRESS_VISITED_COUNTRY = 4;
 
         /** @hide */
+        @IntDef({
+                EPDG_PLMN_RPLMN,
+                EPDG_PLMN_HPLMN,
+                EPDG_PLMN_EHPLMN_ALL,
+                EPDG_PLMN_EHPLMN_FIRST
+        })
+        public @interface EpdgAddressPlmnType {}
+
+        /**
+         * Use the Registered PLMN
+         * @hide
+         */
+        public static final int EPDG_PLMN_RPLMN = 0;
+        /**
+         * Use the PLMN derived from IMSI
+         * @hide
+         */
+        public static final int EPDG_PLMN_HPLMN = 1;
+        /**
+         * Use all EHPLMN from SIM EF files
+         * @hide
+         */
+        public static final int EPDG_PLMN_EHPLMN_ALL = 2;
+        /**
+         * Use the first EHPLMN from SIM EF files
+         * @hide
+         */
+        public static final int EPDG_PLMN_EHPLMN_FIRST = 3;
+
+        /** @hide */
         @IntDef({ID_TYPE_FQDN, ID_TYPE_RFC822_ADDR, ID_TYPE_KEY_ID})
         public @interface IkeIdType {}
 
@@ -8988,6 +9028,12 @@
             defaults.putIntArray(
                     KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
                     new int[] {EPDG_ADDRESS_PLMN, EPDG_ADDRESS_STATIC});
+            defaults.putIntArray(
+                    KEY_EPDG_PLMN_PRIORITY_INT_ARRAY,
+                    new int[]{
+                            EPDG_PLMN_RPLMN,
+                            EPDG_PLMN_HPLMN,
+                            EPDG_PLMN_EHPLMN_ALL});
             defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[0]);
             defaults.putInt(KEY_IKE_LOCAL_ID_TYPE_INT, ID_TYPE_RFC822_ADDR);
             defaults.putInt(KEY_IKE_REMOTE_ID_TYPE_INT, ID_TYPE_FQDN);
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
index 9bfeb63..fe397d9 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.wifi.sharedconnectivity.service.SharedConnectivityService;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -86,6 +87,7 @@
     @Nullable
     @SecurityType
     private final ArraySet<Integer> mHotspotSecurityTypes;
+    private final Bundle mExtras;
 
     /**
      * Builder class for {@link HotspotNetwork}.
@@ -102,8 +104,8 @@
         private String mHotspotBssid;
         @Nullable
         @SecurityType
-        private final ArraySet<Integer> mHotspotSecurityTypes =
-                new ArraySet<>();
+        private final ArraySet<Integer> mHotspotSecurityTypes = new ArraySet<>();
+        private Bundle mExtras = Bundle.EMPTY;
 
         /**
          * Set the remote device ID.
@@ -190,6 +192,17 @@
         }
 
         /**
+         * Sets the extras bundle
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
          * Builds the {@link HotspotNetwork} object.
          *
          * @return Returns the built {@link HotspotNetwork} object.
@@ -203,7 +216,8 @@
                     mNetworkName,
                     mHotspotSsid,
                     mHotspotBssid,
-                    mHotspotSecurityTypes);
+                    mHotspotSecurityTypes,
+                    mExtras);
         }
     }
 
@@ -231,7 +245,8 @@
             @NonNull String networkName,
             @Nullable String hotspotSsid,
             @Nullable String hotspotBssid,
-            @Nullable @SecurityType ArraySet<Integer> hotspotSecurityTypes) {
+            @Nullable @SecurityType ArraySet<Integer> hotspotSecurityTypes,
+            @NonNull Bundle extras) {
         validate(deviceId,
                 networkType,
                 networkName,
@@ -243,6 +258,7 @@
         mHotspotSsid = hotspotSsid;
         mHotspotBssid = hotspotBssid;
         mHotspotSecurityTypes = new ArraySet<>(hotspotSecurityTypes);
+        mExtras = extras;
     }
 
     /**
@@ -315,6 +331,16 @@
         return mHotspotSecurityTypes;
     }
 
+    /**
+     * Gets the extras Bundle.
+     *
+     * @return Returns a Bundle object.
+     */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof HotspotNetwork)) return false;
@@ -348,6 +374,7 @@
         dest.writeString(mHotspotSsid);
         dest.writeString(mHotspotBssid);
         dest.writeArraySet(mHotspotSecurityTypes);
+        dest.writeBundle(mExtras);
     }
 
     /**
@@ -359,7 +386,7 @@
     public static HotspotNetwork readFromParcel(@NonNull Parcel in) {
         return new HotspotNetwork(in.readLong(), NetworkProviderInfo.readFromParcel(in),
                 in.readInt(), in.readString(), in.readString(), in.readString(),
-                (ArraySet<Integer>) in.readArraySet(null));
+                (ArraySet<Integer>) in.readArraySet(null), in.readBundle());
     }
 
     @NonNull
@@ -385,6 +412,7 @@
                 .append(", hotspotSsid=").append(mHotspotSsid)
                 .append(", hotspotBssid=").append(mHotspotBssid)
                 .append(", hotspotSecurityTypes=").append(mHotspotSecurityTypes.toString())
+                .append(", extras=").append(mExtras.toString())
                 .append("]").toString();
     }
 }
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
index 69767f3..72acf2c 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
@@ -117,7 +117,7 @@
         @ConnectionStatus
         private int mStatus;
         private HotspotNetwork mHotspotNetwork;
-        private Bundle mExtras;
+        private Bundle mExtras = Bundle.EMPTY;
 
         /**
          * Sets the status of the connection
@@ -179,7 +179,7 @@
     }
 
     private HotspotNetworkConnectionStatus(@ConnectionStatus int status,
-            HotspotNetwork hotspotNetwork, Bundle extras) {
+            HotspotNetwork hotspotNetwork, @NonNull Bundle extras) {
         validate(status);
         mStatus = status;
         mHotspotNetwork = hotspotNetwork;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
index 64412bc..c390e42 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -73,6 +74,7 @@
     @SecurityType
     private final ArraySet<Integer> mSecurityTypes;
     private final NetworkProviderInfo mNetworkProviderInfo;
+    private final Bundle mExtras;
 
     /**
      * Builder class for {@link KnownNetwork}.
@@ -84,6 +86,7 @@
         @SecurityType
         private final ArraySet<Integer> mSecurityTypes = new ArraySet<>();
         private NetworkProviderInfo mNetworkProviderInfo;
+        private Bundle mExtras = Bundle.EMPTY;
 
         /**
          * Sets the indicated source of the known network.
@@ -135,6 +138,17 @@
         }
 
         /**
+         * Sets the extras bundle
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
          * Builds the {@link KnownNetwork} object.
          *
          * @return Returns the built {@link KnownNetwork} object.
@@ -145,7 +159,8 @@
                     mNetworkSource,
                     mSsid,
                     mSecurityTypes,
-                    mNetworkProviderInfo);
+                    mNetworkProviderInfo,
+                    mExtras);
         }
     }
 
@@ -173,12 +188,14 @@
             @NetworkSource int networkSource,
             @NonNull String ssid,
             @NonNull @SecurityType ArraySet<Integer> securityTypes,
-            @Nullable NetworkProviderInfo networkProviderInfo) {
+            @Nullable NetworkProviderInfo networkProviderInfo,
+            @NonNull Bundle extras) {
         validate(networkSource, ssid, securityTypes, networkProviderInfo);
         mNetworkSource = networkSource;
         mSsid = ssid;
         mSecurityTypes = new ArraySet<>(securityTypes);
         mNetworkProviderInfo = networkProviderInfo;
+        mExtras = extras;
     }
 
     /**
@@ -223,6 +240,16 @@
         return mNetworkProviderInfo;
     }
 
+    /**
+     * Gets the extras Bundle.
+     *
+     * @return Returns a Bundle object.
+     */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof KnownNetwork)) return false;
@@ -249,6 +276,7 @@
         dest.writeString(mSsid);
         dest.writeArraySet(mSecurityTypes);
         mNetworkProviderInfo.writeToParcel(dest, flags);
+        dest.writeBundle(mExtras);
     }
 
     /**
@@ -260,7 +288,7 @@
     public static KnownNetwork readFromParcel(@NonNull Parcel in) {
         return new KnownNetwork(in.readInt(), in.readString(),
                 (ArraySet<Integer>) in.readArraySet(null),
-                NetworkProviderInfo.readFromParcel(in));
+                NetworkProviderInfo.readFromParcel(in), in.readBundle());
     }
 
     @NonNull
@@ -283,6 +311,7 @@
                 .append(", ssid=").append(mSsid)
                 .append(", securityTypes=").append(mSecurityTypes.toString())
                 .append(", networkProviderInfo=").append(mNetworkProviderInfo.toString())
+                .append(", extras=").append(mExtras.toString())
                 .append("]").toString();
     }
 }
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
index 6bd0a5e..b30dc3f 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
@@ -72,7 +72,7 @@
     public static final class Builder {
         @ConnectionStatus private int mStatus;
         private KnownNetwork mKnownNetwork;
-        private Bundle mExtras;
+        private Bundle mExtras = Bundle.EMPTY;
 
         public Builder() {}
 
@@ -128,7 +128,7 @@
     }
 
     private KnownNetworkConnectionStatus(@ConnectionStatus int status, KnownNetwork knownNetwork,
-            Bundle extras) {
+            @NonNull Bundle extras) {
         validate(status);
         mStatus = status;
         mKnownNetwork = knownNetwork;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
index ed4d699..25fbabc 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.net.wifi.sharedconnectivity.service.SharedConnectivityService;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -89,6 +90,7 @@
     private final String mModelName;
     private final int mBatteryPercentage;
     private final int mConnectionStrength;
+    private final Bundle mExtras;
 
     /**
      * Builder class for {@link NetworkProviderInfo}.
@@ -99,6 +101,7 @@
         private String mModelName;
         private int mBatteryPercentage;
         private int mConnectionStrength;
+        private Bundle mExtras = Bundle.EMPTY;
 
         public Builder(@NonNull String deviceName, @NonNull String modelName) {
             Objects.requireNonNull(deviceName);
@@ -170,6 +173,17 @@
         }
 
         /**
+         * Sets the extras bundle
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
          * Builds the {@link NetworkProviderInfo} object.
          *
          * @return Returns the built {@link NetworkProviderInfo} object.
@@ -177,7 +191,7 @@
         @NonNull
         public NetworkProviderInfo build() {
             return new NetworkProviderInfo(mDeviceType, mDeviceName, mModelName, mBatteryPercentage,
-                    mConnectionStrength);
+                    mConnectionStrength, mExtras);
         }
     }
 
@@ -197,13 +211,15 @@
     }
 
     private NetworkProviderInfo(@DeviceType int deviceType, @NonNull String deviceName,
-            @NonNull String modelName, int batteryPercentage, int connectionStrength) {
+            @NonNull String modelName, int batteryPercentage, int connectionStrength,
+            @NonNull Bundle extras) {
         validate(deviceType, deviceName, modelName, batteryPercentage, connectionStrength);
         mDeviceType = deviceType;
         mDeviceName = deviceName;
         mModelName = modelName;
         mBatteryPercentage = batteryPercentage;
         mConnectionStrength = connectionStrength;
+        mExtras = extras;
     }
 
     /**
@@ -256,6 +272,16 @@
         return mConnectionStrength;
     }
 
+    /**
+     * Gets the extras Bundle.
+     *
+     * @return Returns a Bundle object.
+     */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof NetworkProviderInfo)) return false;
@@ -280,6 +306,7 @@
         dest.writeString(mModelName);
         dest.writeInt(mBatteryPercentage);
         dest.writeInt(mConnectionStrength);
+        dest.writeBundle(mExtras);
     }
 
     @Override
@@ -295,7 +322,7 @@
     @NonNull
     public static NetworkProviderInfo readFromParcel(@NonNull Parcel in) {
         return new NetworkProviderInfo(in.readInt(), in.readString(), in.readString(), in.readInt(),
-                in.readInt());
+                in.readInt(), in.readBundle());
     }
 
     @NonNull
@@ -319,6 +346,7 @@
                 .append(", modelName=").append(mModelName)
                 .append(", batteryPercentage=").append(mBatteryPercentage)
                 .append(", connectionStrength=").append(mConnectionStrength)
+                .append(", extras=").append(mExtras.toString())
                 .append("]").toString();
     }
 }
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
index 63e471b..30bb989 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
@@ -51,7 +51,7 @@
         private boolean mInstantTetherEnabled;
         private Intent mInstantTetherSettingsIntent;
         private final Context mContext;
-        private Bundle mExtras;
+        private Bundle mExtras = Bundle.EMPTY;
 
         public Builder(@NonNull Context context) {
             mContext = context;
@@ -112,8 +112,7 @@
     }
 
     private SharedConnectivitySettingsState(boolean instantTetherEnabled,
-            PendingIntent pendingIntent, Bundle extras) {
-
+            PendingIntent pendingIntent, @NonNull Bundle extras) {
         mInstantTetherEnabled = instantTetherEnabled;
         mInstantTetherSettingsPendingIntent = pendingIntent;
         mExtras = extras;
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
index 8302094..0827ffa 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
@@ -28,6 +28,7 @@
 
 import static org.junit.Assert.assertThrows;
 
+import android.os.Bundle;
 import android.os.Parcel;
 import android.util.ArraySet;
 
@@ -55,6 +56,8 @@
     private static final String HOTSPOT_SSID = "TEST_SSID";
     private static final String HOTSPOT_BSSID = "TEST _BSSID";
     private static final int[] HOTSPOT_SECURITY_TYPES = {SECURITY_TYPE_WEP, SECURITY_TYPE_EAP};
+    private static final String BUNDLE_KEY = "INT-KEY";
+    private static final int BUNDLE_VALUE = 1;
 
     private static final long DEVICE_ID_1 = 111L;
     private static final NetworkProviderInfo NETWORK_PROVIDER_INFO1 =
@@ -138,6 +141,7 @@
         assertThat(network.getHotspotSsid()).isEqualTo(HOTSPOT_SSID);
         assertThat(network.getHotspotBssid()).isEqualTo(HOTSPOT_BSSID);
         assertThat(network.getHotspotSecurityTypes()).containsExactlyElementsIn(securityTypes);
+        assertThat(network.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE);
     }
 
     @Test
@@ -161,11 +165,18 @@
                 .setHostNetworkType(NETWORK_TYPE)
                 .setNetworkName(NETWORK_NAME)
                 .setHotspotSsid(HOTSPOT_SSID)
-                .setHotspotBssid(HOTSPOT_BSSID);
+                .setHotspotBssid(HOTSPOT_BSSID)
+                .setExtras(buildBundle());
         Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(builder::addHotspotSecurityType);
         if (withNetworkProviderInfo) {
             builder.setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
         }
         return builder;
     }
+
+    private Bundle buildBundle() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(BUNDLE_KEY, BUNDLE_VALUE);
+        return bundle;
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
index 1ecba76..81d7b44 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
@@ -25,6 +25,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.os.Bundle;
 import android.os.Parcel;
 import android.util.ArraySet;
 
@@ -47,6 +48,9 @@
             new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
                     .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
                     .setBatteryPercentage(50).build();
+    private static final String BUNDLE_KEY = "INT-KEY";
+    private static final int BUNDLE_VALUE = 1;
+
     private static final int NETWORK_SOURCE_1 = NETWORK_SOURCE_CLOUD_SELF;
     private static final String SSID_1 = "TEST_SSID1";
     private static final int[] SECURITY_TYPES_1 = {SECURITY_TYPE_PSK};
@@ -113,6 +117,7 @@
         assertThat(network.getSsid()).isEqualTo(SSID);
         assertThat(network.getSecurityTypes()).containsExactlyElementsIn(securityTypes);
         assertThat(network.getNetworkProviderInfo()).isEqualTo(NETWORK_PROVIDER_INFO);
+        assertThat(network.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE);
     }
 
     @Test
@@ -125,8 +130,15 @@
 
     private KnownNetwork.Builder buildKnownNetworkBuilder() {
         KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
-                .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
+                .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO)
+                .setExtras(buildBundle());
         Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType);
         return builder;
     }
+
+    private Bundle buildBundle() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(BUNDLE_KEY, BUNDLE_VALUE);
+        return bundle;
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
index 8f35d8d..4aa9ca6 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
@@ -21,6 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.os.Bundle;
 import android.os.Parcel;
 
 import androidx.test.filters.SmallTest;
@@ -38,6 +39,8 @@
     private static final String DEVICE_MODEL = "TEST_MODEL";
     private static final int BATTERY_PERCENTAGE = 50;
     private static final int CONNECTION_STRENGTH = 2;
+    private static final String BUNDLE_KEY = "INT-KEY";
+    private static final int BUNDLE_VALUE = 1;
 
     private static final int DEVICE_TYPE_1 = DEVICE_TYPE_LAPTOP;
     private static final String DEVICE_NAME_1 = "TEST_NAME1";
@@ -105,6 +108,7 @@
         assertThat(info.getModelName()).isEqualTo(DEVICE_MODEL);
         assertThat(info.getBatteryPercentage()).isEqualTo(BATTERY_PERCENTAGE);
         assertThat(info.getConnectionStrength()).isEqualTo(CONNECTION_STRENGTH);
+        assertThat(info.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE);
     }
 
     @Test
@@ -118,6 +122,13 @@
     private NetworkProviderInfo.Builder buildNetworkProviderInfoBuilder() {
         return new NetworkProviderInfo.Builder(DEVICE_NAME, DEVICE_MODEL).setDeviceType(DEVICE_TYPE)
                 .setBatteryPercentage(BATTERY_PERCENTAGE)
-                .setConnectionStrength(CONNECTION_STRENGTH);
+                .setConnectionStrength(CONNECTION_STRENGTH)
+                .setExtras(buildBundle());
+    }
+
+    private Bundle buildBundle() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(BUNDLE_KEY, BUNDLE_VALUE);
+        return bundle;
     }
 }