Merge "Fix tts span on Editable"
diff --git a/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl b/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
index 9d11ca4..25caf4b 100644
--- a/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
+++ b/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
@@ -40,7 +40,6 @@
     long getNextWakeFromIdleTime();
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
-    long currentNetworkTimeMillis();
     boolean canScheduleExactAlarms(String packageName);
     boolean hasScheduleExactAlarm(String packageName, int userId);
     int getConfigVersion();
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 296c89c..c053b2e 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -90,7 +90,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.ParcelableException;
 import android.os.PowerExemptionManager;
 import android.os.PowerManager;
 import android.os.Process;
@@ -116,7 +115,6 @@
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.LongArrayQueue;
-import android.util.NtpTrustedTime;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -161,7 +159,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
-import java.time.DateTimeException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -3008,17 +3005,6 @@
         }
 
         @Override
-        public long currentNetworkTimeMillis() {
-            final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext());
-            NtpTrustedTime.TimeResult ntpResult = time.getCachedTimeResult();
-            if (ntpResult != null) {
-                return ntpResult.currentTimeMillis();
-            } else {
-                throw new ParcelableException(new DateTimeException("Missing NTP fix"));
-            }
-        }
-
-        @Override
         public int getConfigVersion() {
             getContext().enforceCallingOrSelfPermission(Manifest.permission.DUMP,
                     "getConfigVersion");
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index a3a3615..f29998a 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -290,10 +290,10 @@
             }
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
         @Override
         public void editProperties(IAccountAuthenticatorResponse response,
                 String accountType) throws RemoteException {
-            checkBinderPermission();
             try {
                 final Bundle result = AbstractAccountAuthenticator.this.editProperties(
                     new AccountAuthenticatorResponse(response), accountType);
@@ -305,10 +305,10 @@
             }
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
         @Override
         public void hasFeatures(IAccountAuthenticatorResponse response,
                 Account account, String[] features) throws RemoteException {
-            checkBinderPermission();
             try {
                 final Bundle result = AbstractAccountAuthenticator.this.hasFeatures(
                     new AccountAuthenticatorResponse(response), account, features);
@@ -320,10 +320,10 @@
             }
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
         @Override
         public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
                 Account account) throws RemoteException {
-            checkBinderPermission();
             try {
                 final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed(
                     new AccountAuthenticatorResponse(response), account);
@@ -335,10 +335,10 @@
             }
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
         @Override
         public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
                 Account account) throws RemoteException {
-            checkBinderPermission();
             try {
                 final Bundle result =
                         AbstractAccountAuthenticator.this.getAccountCredentialsForCloning(
@@ -351,11 +351,11 @@
             }
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
         @Override
         public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
                 Account account,
                 Bundle accountCredentials) throws RemoteException {
-            checkBinderPermission();
             try {
                 final Bundle result =
                         AbstractAccountAuthenticator.this.addAccountFromCredentials(
@@ -465,12 +465,12 @@
             }
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
         @Override
         public void isCredentialsUpdateSuggested(
                 IAccountAuthenticatorResponse response,
                 Account account,
                 String statusToken) throws RemoteException {
-            checkBinderPermission();
             try {
                 final Bundle result = AbstractAccountAuthenticator.this
                         .isCredentialsUpdateSuggested(
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
index 701cecf..0575c07 100644
--- a/core/java/android/accounts/IAccountAuthenticator.aidl
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -62,6 +62,7 @@
     /**
      * launches an activity that lets the user edit and set the properties for an authenticator
      */
+    @EnforcePermission("ACCOUNT_MANAGER")
     @UnsupportedAppUsage
     void editProperties(in IAccountAuthenticatorResponse response, String accountType);
 
@@ -69,6 +70,7 @@
      * returns a Bundle where the boolean value BOOLEAN_RESULT_KEY is set if the account has the
      * specified features
      */
+    @EnforcePermission("ACCOUNT_MANAGER")
     @UnsupportedAppUsage
     void hasFeatures(in IAccountAuthenticatorResponse response, in Account account, 
         in String[] features);
@@ -76,12 +78,14 @@
     /**
      * Gets whether or not the account is allowed to be removed.
      */
+    @EnforcePermission("ACCOUNT_MANAGER")
     @UnsupportedAppUsage
     void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);
 
     /**
      * Returns a Bundle containing the required credentials to copy the account across users.
      */
+    @EnforcePermission("ACCOUNT_MANAGER")
     void getAccountCredentialsForCloning(in IAccountAuthenticatorResponse response,
             in Account account);
 
@@ -89,6 +93,7 @@
      * Uses the Bundle containing credentials from another instance of the authenticator to create
      * a copy of the account on this user.
      */
+    @EnforcePermission("ACCOUNT_MANAGER")
     void addAccountFromCredentials(in IAccountAuthenticatorResponse response, in Account account,
             in Bundle accountCredentials);
 
@@ -116,6 +121,7 @@
     /**
      * Checks if the credentials of the provided account should be updated.
      */
+    @EnforcePermission("ACCOUNT_MANAGER")
     void isCredentialsUpdateSuggested(in IAccountAuthenticatorResponse response, in Account account,
         String statusToken);
 }
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index fc7afb4..b441359 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -24,6 +24,7 @@
 import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.NetworkTimeSuggestion;
 import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timedetector.TimePoint;
 
 /**
  * System private API to communicate with time detector service.
@@ -45,9 +46,11 @@
 
   boolean updateConfiguration(in TimeConfiguration timeConfiguration);
 
-  void suggestExternalTime( in ExternalTimeSuggestion timeSuggestion);
+  void suggestExternalTime(in ExternalTimeSuggestion timeSuggestion);
   void suggestGnssTime(in GnssTimeSuggestion timeSuggestion);
   boolean suggestManualTime(in ManualTimeSuggestion timeSuggestion);
   void suggestNetworkTime(in NetworkTimeSuggestion timeSuggestion);
   void suggestTelephonyTime(in TelephonyTimeSuggestion timeSuggestion);
+
+  TimePoint latestNetworkTime();
 }
diff --git a/core/java/android/app/timedetector/TimePoint.aidl b/core/java/android/app/timedetector/TimePoint.aidl
new file mode 100644
index 0000000..80d4bc1
--- /dev/null
+++ b/core/java/android/app/timedetector/TimePoint.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+parcelable TimePoint;
diff --git a/core/java/android/app/timedetector/TimePoint.java b/core/java/android/app/timedetector/TimePoint.java
new file mode 100644
index 0000000..aa079a9
--- /dev/null
+++ b/core/java/android/app/timedetector/TimePoint.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Data class for passing a Unix epoch time anchored to the elapsed realtime clock.
+ *
+ * @hide
+ */
+public final class TimePoint implements Parcelable {
+
+    private final long mUnixEpochTimeMillis;
+    private final long mElapsedRealtimeMillis;
+
+    public TimePoint(long unixEpochTimeMillis, long elapsedRealtimeMillis) {
+        mUnixEpochTimeMillis = unixEpochTimeMillis;
+        mElapsedRealtimeMillis = elapsedRealtimeMillis;
+    }
+
+    /**
+     * The current Unix epoch time, according to the external source.
+     */
+    public long getUnixEpochTimeMillis() {
+        return mUnixEpochTimeMillis;
+    }
+
+    /**
+     * The elapsed millis since boot when {@link #getUnixEpochTimeMillis} was computed.
+     */
+    public long getElapsedRealtimeMillis() {
+        return mElapsedRealtimeMillis;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mUnixEpochTimeMillis);
+        out.writeLong(mElapsedRealtimeMillis);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof TimePoint)) {
+            return false;
+        }
+        TimePoint timePoint = (TimePoint) o;
+        return mUnixEpochTimeMillis == timePoint.mUnixEpochTimeMillis
+                && mElapsedRealtimeMillis == timePoint.mElapsedRealtimeMillis;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUnixEpochTimeMillis, mElapsedRealtimeMillis);
+    }
+
+    @Override
+    public String toString() {
+        return "TimePoint{"
+                + "mUnixEpochTimeMillis=" + mUnixEpochTimeMillis
+                + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
+                + '}';
+    }
+
+    public static final @NonNull Creator<TimePoint> CREATOR =
+            new Creator<TimePoint>() {
+                public TimePoint createFromParcel(Parcel in) {
+                    long unixEpochTime = in.readLong();
+                    long elapsedRealtimeMillis = in.readLong();
+                    return new TimePoint(unixEpochTime, elapsedRealtimeMillis);
+                }
+
+                public TimePoint[] newArray(int size) {
+                    return new TimePoint[size];
+                }
+            };
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 4d0ba63..336ef7a 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -1739,6 +1739,20 @@
                     // abruptly.
                     Log.w(TAG, "Output surface likely abandoned, dropping buffer!");
                     img.close();
+                } catch (RuntimeException e) {
+                    // NOTE: This is intended to catch RuntimeException from ImageReader.detachImage
+                    // ImageReader.detachImage is not supposed to throw RuntimeExceptions but the
+                    // bug went unchecked for a few years and now its behavior cannot be changed
+                    // without breaking backwards compatibility.
+
+                    if (!e.getClass().equals(RuntimeException.class)) {
+                        // re-throw any exceptions that aren't base RuntimeException since they are
+                        // coming from elsewhere, and we shouldn't silently drop those.
+                        throw e;
+                    }
+
+                    Log.w(TAG, "Output surface likely abandoned, dropping buffer!");
+                    img.close();
                 }
             }
         }
@@ -1773,9 +1787,23 @@
                 }
                 try {
                     reader.detachImage(img);
-                } catch (Exception e) {
-                    Log.e(TAG,
-                            "Failed to detach image!");
+                } catch (IllegalStateException e) {
+                    Log.e(TAG, "Failed to detach image!");
+                    img.close();
+                    return;
+                } catch (RuntimeException e) {
+                    // NOTE: This is intended to catch RuntimeException from ImageReader.detachImage
+                    // ImageReader.detachImage is not supposed to throw RuntimeExceptions but the
+                    // bug went unchecked for a few years and now its behavior cannot be changed
+                    // without breaking backwards compatibility.
+
+                    if (!e.getClass().equals(RuntimeException.class)) {
+                        // re-throw any exceptions that aren't base RuntimeException since they are
+                        // coming from elsewhere, and we shouldn't silently drop those.
+                        throw e;
+                    }
+
+                    Log.e(TAG, "Failed to detach image!");
                     img.close();
                     return;
                 }
diff --git a/core/java/android/hardware/location/ActivityRecognitionHardware.java b/core/java/android/hardware/location/ActivityRecognitionHardware.java
index 8acd1ff..20d6338 100644
--- a/core/java/android/hardware/location/ActivityRecognitionHardware.java
+++ b/core/java/android/hardware/location/ActivityRecognitionHardware.java
@@ -88,34 +88,34 @@
         return nativeIsSupported();
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
     @Override
     public String[] getSupportedActivities() {
-        checkPermissions();
         return mSupportedActivities;
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
     @Override
     public boolean isActivitySupported(String activity) {
-        checkPermissions();
         int activityType = getActivityType(activity);
         return activityType != INVALID_ACTIVITY_TYPE;
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
     @Override
     public boolean registerSink(IActivityRecognitionHardwareSink sink) {
-        checkPermissions();
         return mSinks.register(sink);
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
     @Override
     public boolean unregisterSink(IActivityRecognitionHardwareSink sink) {
-        checkPermissions();
         return mSinks.unregister(sink);
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
     @Override
     public boolean enableActivityEvent(String activity, int eventType, long reportLatencyNs) {
-        checkPermissions();
 
         int activityType = getActivityType(activity);
         if (activityType == INVALID_ACTIVITY_TYPE) {
@@ -130,9 +130,9 @@
         return false;
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
     @Override
     public boolean disableActivityEvent(String activity, int eventType) {
-        checkPermissions();
 
         int activityType = getActivityType(activity);
         if (activityType == INVALID_ACTIVITY_TYPE) {
@@ -147,9 +147,9 @@
         return false;
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
     @Override
     public boolean flush() {
-        checkPermissions();
         int result = nativeFlush();
         return result == NATIVE_SUCCESS_RESULT;
     }
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index c0bcb27..106bfd5 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -75,76 +75,68 @@
             mGeofenceHardwareImpl.setFusedGeofenceHardware(service);
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public int[] getMonitoringTypes() {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
 
             return mGeofenceHardwareImpl.getMonitoringTypes();
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public int getStatusOfMonitoringType(int monitoringType) {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
 
             return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType);
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public boolean addCircularFence(
                 int monitoringType,
                 GeofenceHardwareRequestParcelable request,
                 IGeofenceHardwareCallback callback) {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
             return mGeofenceHardwareImpl.addCircularFence(monitoringType, request, callback);
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public boolean removeGeofence(int id, int monitoringType) {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
 
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
             return mGeofenceHardwareImpl.removeGeofence(id, monitoringType);
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public boolean pauseGeofence(int id, int monitoringType) {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
 
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
             return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
 
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
             return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions);
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public boolean registerForMonitorStateChangeCallback(int monitoringType,
                 IGeofenceHardwareMonitorCallback callback) {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
 
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
             return mGeofenceHardwareImpl.registerForMonitorStateChangeCallback(monitoringType,
                     callback);
         }
 
+        @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
         @Override
         public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
                 IGeofenceHardwareMonitorCallback callback) {
-            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
-                    "Location Hardware permission not granted to access hardware geofence");
 
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
             return mGeofenceHardwareImpl.unregisterForMonitorStateChangeCallback(monitoringType,
diff --git a/core/java/android/hardware/location/IActivityRecognitionHardware.aidl b/core/java/android/hardware/location/IActivityRecognitionHardware.aidl
index bc6b183..f093cd5 100644
--- a/core/java/android/hardware/location/IActivityRecognitionHardware.aidl
+++ b/core/java/android/hardware/location/IActivityRecognitionHardware.aidl
@@ -28,35 +28,42 @@
     /**
      * Gets an array of supported activities by hardware.
      */
+    @EnforcePermission("LOCATION_HARDWARE")
     String[] getSupportedActivities();
 
     /**
      * Returns true if the given activity is supported, false otherwise.
      */
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean isActivitySupported(in String activityType);
 
     /**
      * Registers a sink with Hardware Activity-Recognition.
      */
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean registerSink(in IActivityRecognitionHardwareSink sink);
 
     /**
      * Unregisters a sink with Hardware Activity-Recognition.
      */
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean unregisterSink(in IActivityRecognitionHardwareSink sink);
 
     /**
      * Enables tracking of a given activity/event type, if the activity is supported.
      */
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean enableActivityEvent(in String activityType, int eventType, long reportLatencyNs);
 
     /**
      * Disables tracking of a given activity/eventy type.
      */
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean disableActivityEvent(in String activityType, int eventType);
 
     /**
      * Requests hardware for all the activity events detected up to the given point in time.
      */
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean flush();
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
index 0e840c4..41804ad 100644
--- a/core/java/android/hardware/location/IGeofenceHardware.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -26,17 +26,25 @@
 interface IGeofenceHardware {
     void setGpsGeofenceHardware(in IGpsGeofenceHardware service);
     void setFusedGeofenceHardware(in IFusedGeofenceHardware service);
+    @EnforcePermission("LOCATION_HARDWARE")
     int[] getMonitoringTypes();
+    @EnforcePermission("LOCATION_HARDWARE")
     int getStatusOfMonitoringType(int monitoringType);
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean addCircularFence(
             int monitoringType,
             in GeofenceHardwareRequestParcelable request,
             in IGeofenceHardwareCallback callback);
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean removeGeofence(int id, int monitoringType);
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean pauseGeofence(int id, int monitoringType);
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean resumeGeofence(int id, int monitoringType, int monitorTransitions);
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean registerForMonitorStateChangeCallback(int monitoringType,
             IGeofenceHardwareMonitorCallback callback);
+    @EnforcePermission("LOCATION_HARDWARE")
     boolean unregisterForMonitorStateChangeCallback(int monitoringType,
             IGeofenceHardwareMonitorCallback callback);
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c02f870..c6fc9ec 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2163,13 +2163,13 @@
             mCandidatesVisibility = vis;
         }
     }
-    
+
     /**
      * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
      * or {@link View#GONE View.GONE}) of the candidates view when it is not
      * shown.  The default implementation returns GONE when
      * {@link #isExtractViewShown} returns true,
-     * otherwise VISIBLE.  Be careful if you change this to return GONE in
+     * otherwise INVISIBLE.  Be careful if you change this to return GONE in
      * other situations -- if showing or hiding the candidates view causes
      * your window to resize, this can cause temporary drawing artifacts as
      * the resize takes place.
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 7379443..ecea054 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.app.IAlarmManager;
+import android.app.timedetector.ITimeDetectorService;
+import android.app.timedetector.TimePoint;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.location.ILocationManager;
@@ -170,6 +172,14 @@
         return false;
     }
 
+    private static IAlarmManager getIAlarmManager() {
+        if (sIAlarmManager == null) {
+            sIAlarmManager = IAlarmManager.Stub
+                    .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+        }
+        return sIAlarmManager;
+    }
+
     /**
      * Returns milliseconds since boot, not counting time spent in deep sleep.
      *
@@ -269,56 +279,71 @@
      * <p>
      * While the time returned by {@link System#currentTimeMillis()} can be
      * adjusted by the user, the time returned by this method cannot be adjusted
-     * by the user. Note that synchronization may occur using an insecure
-     * network protocol, so the returned time should not be used for security
-     * purposes.
+     * by the user.
      * <p>
      * This performs no blocking network operations and returns values based on
      * a recent successful synchronization event; it will either return a valid
      * time or throw.
+     * <p>
+     * Note that synchronization may occur using an insecure network protocol,
+     * so the returned time should not be used for security purposes.
+     * The device may resynchronize with the same or different network source
+     * at any time. Due to network delays, variations between servers, or local
+     * (client side) clock drift, the accuracy of the returned times cannot be
+     * guaranteed. In extreme cases, consecutive calls to {@link
+     * #currentNetworkTimeMillis()} could return times that are out of order.
      *
-     * @throws DateTimeException when no accurate network time can be provided.
+     * @throws DateTimeException when no network time can be provided.
      * @hide
      */
     public static long currentNetworkTimeMillis() {
-        final IAlarmManager mgr = getIAlarmManager();
-        if (mgr != null) {
+        ITimeDetectorService timeDetectorService = ITimeDetectorService.Stub
+                .asInterface(ServiceManager.getService(Context.TIME_DETECTOR_SERVICE));
+        if (timeDetectorService != null) {
+            TimePoint time;
             try {
-                return mgr.currentNetworkTimeMillis();
+                time = timeDetectorService.latestNetworkTime();
             } catch (ParcelableException e) {
                 e.maybeRethrow(DateTimeException.class);
                 throw new RuntimeException(e);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
+
+            if (time == null) {
+                // This is not expected.
+                throw new DateTimeException("Network based time is not available.");
+            }
+            long currentMillis = elapsedRealtime();
+            long deltaMs = currentMillis - time.getElapsedRealtimeMillis();
+            return time.getUnixEpochTimeMillis() + deltaMs;
         } else {
             throw new RuntimeException(new DeadSystemException());
         }
     }
 
-    private static IAlarmManager getIAlarmManager() {
-        if (sIAlarmManager == null) {
-            sIAlarmManager = IAlarmManager.Stub
-                    .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
-        }
-        return sIAlarmManager;
-    }
-
-    /**
+   /**
      * Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC,
      * synchronized using a remote network source outside the device.
      * <p>
      * While the time returned by {@link System#currentTimeMillis()} can be
      * adjusted by the user, the time returned by this method cannot be adjusted
-     * by the user. Note that synchronization may occur using an insecure
-     * network protocol, so the returned time should not be used for security
-     * purposes.
+     * by the user.
      * <p>
      * This performs no blocking network operations and returns values based on
      * a recent successful synchronization event; it will either return a valid
      * time or throw.
+     * <p>
+     * Note that synchronization may occur using an insecure network protocol,
+     * so the returned time should not be used for security purposes.
+     * The device may resynchronize with the same or different network source
+     * at any time. Due to network delays, variations between servers, or local
+     * (client side) clock drift, the accuracy of the returned times cannot be
+     * guaranteed. In extreme cases, consecutive calls to {@link
+     * Clock#millis()} on the returned {@link Clock}could return times that are
+     * out of order.
      *
-     * @throws DateTimeException when no accurate network time can be provided.
+     * @throws DateTimeException when no network time can be provided.
      */
     public static @NonNull Clock currentNetworkTimeClock() {
         return new SimpleClock(ZoneOffset.UTC) {
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 4e7b3a5..4a3f772 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -55,18 +55,19 @@
      * @hide
      */
     public static class TimeResult {
-        private final long mTimeMillis;
+        private final long mUnixEpochTimeMillis;
         private final long mElapsedRealtimeMillis;
         private final long mCertaintyMillis;
 
-        public TimeResult(long timeMillis, long elapsedRealtimeMillis, long certaintyMillis) {
-            mTimeMillis = timeMillis;
+        public TimeResult(
+                long unixEpochTimeMillis, long elapsedRealtimeMillis, long certaintyMillis) {
+            mUnixEpochTimeMillis = unixEpochTimeMillis;
             mElapsedRealtimeMillis = elapsedRealtimeMillis;
             mCertaintyMillis = certaintyMillis;
         }
 
         public long getTimeMillis() {
-            return mTimeMillis;
+            return mUnixEpochTimeMillis;
         }
 
         public long getElapsedRealtimeMillis() {
@@ -77,9 +78,11 @@
             return mCertaintyMillis;
         }
 
-        /** Calculates and returns the current time accounting for the age of this result. */
+        /**
+         * Calculates and returns the current Unix epoch time accounting for the age of this result.
+         */
         public long currentTimeMillis() {
-            return mTimeMillis + getAgeMillis();
+            return mUnixEpochTimeMillis + getAgeMillis();
         }
 
         /** Calculates and returns the age of this result. */
@@ -99,7 +102,7 @@
         @Override
         public String toString() {
             return "TimeResult{"
-                    + "mTimeMillis=" + Instant.ofEpochMilli(mTimeMillis)
+                    + "mUnixEpochTimeMillis=" + Instant.ofEpochMilli(mUnixEpochTimeMillis)
                     + ", mElapsedRealtimeMillis=" + Duration.ofMillis(mElapsedRealtimeMillis)
                     + ", mCertaintyMillis=" + mCertaintyMillis
                     + '}';
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 872e65a..07dfce7 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -61,22 +61,32 @@
 import com.android.internal.R;
 
 /**
- * A Switch is a two-state toggle switch widget that can select between two
- * options. The user may drag the "thumb" back and forth to choose the selected option,
- * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
- * property controls the text displayed in the label for the switch, whereas the
- * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
- * controls the text on the thumb. Similarly, the
- * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
- * setTypeface() methods control the typeface and style of label text, whereas the
- * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
- * the related setSwitchTypeface() methods control that of the thumb.
+ * A Switch is a two-state toggle widget. Users can drag the switch "thumb" back
+ * and forth to select either of two options or simply tap the switch to toggle
+ * between options.
  *
- * <p>{@link androidx.recyclerview.widget.RecyclerView} is a version of
- * the Switch widget which runs on devices back to API 7.</p>
+ * <p>The {@link #setText(CharSequence) text} property controls
+ * the text of the switch label. The {@link #setTextOn(CharSequence) textOn} and
+ * {@link #setTextOff(CharSequence) textOff} properties control the text of the
+ * thumb. The {@link #setTextAppearance(int) textAppearance} property and the
+ * related {@link #setTypeface(android.graphics.Typeface) setTypeface()} methods
+ * control the typeface and style of the switch label. The
+ * {@link #setSwitchTextAppearance(android.content.Context, int)
+ * switchTextAppearance} property and the related
+ * {@link #setSwitchTypeface(android.graphics.Typeface) setSwitchTypeface()}
+ * methods control the typeface and style of the thumb text.</p>
  *
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
- * guide.</p>
+ * <p class="note"><b>Note:</b> The thumb text is displayed only if the
+ * <a href="{@docRoot}reference/android/widget/Switch#attr_android:showText">
+ * <code>showText</code></a> attribute is set to {@code true}. See also
+ * {@link #setShowText(boolean)} and {@link #getShowText()}.</p>
+ *
+ * <p>{@link androidx.appcompat.widget.SwitchCompat} provides backward
+ * compatibility down to Android 4.0 (API level 14).</p>
+ *
+ * <p>For more information, see the
+ * <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">
+ * Toggle Buttons</a> guide.</p>
  *
  * @attr ref android.R.styleable#Switch_textOn
  * @attr ref android.R.styleable#Switch_textOff
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index acadac7..bb4ab39 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -549,6 +549,11 @@
        return NULL;
     }
 
+    if (parcel->isForRpc()) {
+        jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall an RPC Parcel.");
+        return NULL;
+    }
+
     if (parcel->objectsCount())
     {
         jniThrowException(env, "java/lang/RuntimeException",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
index 14ba9df..764e650 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -85,6 +85,8 @@
         }
 
         mDisplayAreasInfo.remove(displayId);
+        mLeashes.get(displayId).release();
+        mLeashes.remove(displayId);
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index fb61861..9df8251 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -530,7 +530,8 @@
             }
 
             final int taskId = taskInfo.taskId;
-            final TaskListener listener = getTaskListener(mTasks.get(taskId).getTaskInfo());
+            final TaskAppearedInfo appearedInfo = mTasks.get(taskId);
+            final TaskListener listener = getTaskListener(appearedInfo.getTaskInfo());
             mTasks.remove(taskId);
             if (listener != null) {
                 listener.onTaskVanished(taskInfo);
@@ -540,6 +541,10 @@
             notifyCompatUI(taskInfo, null /* taskListener */);
             // Notify the recent tasks that a task has been removed
             mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
+
+            if (appearedInfo.getLeash() != null) {
+                appearedInfo.getLeash().release();
+            }
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index f061f8b..e35e4ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -406,7 +406,9 @@
     private boolean shouldDispatchToLauncher(int backType) {
         return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
                 && mBackToLauncherCallback != null
-                && mEnableAnimations.get();
+                && mEnableAnimations.get()
+                && mBackNavigationInfo != null
+                && mBackNavigationInfo.getDepartingAnimationTarget() != null;
     }
 
     private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
index 3f7d78d..9478b34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -128,9 +128,10 @@
 
             final WindowContainerTransaction wct = new WindowContainerTransaction();
             final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-            applyBoundsAndOffsets(
-                    displayAreaInfo.token, mDisplayAreaMap.get(displayAreaInfo.token), wct, t);
+            final SurfaceControl leash = mDisplayAreaMap.get(displayAreaInfo.token);
+            applyBoundsAndOffsets(displayAreaInfo.token, leash, wct, t);
             applyTransaction(wct, t);
+            leash.release();
             mDisplayAreaMap.remove(displayAreaInfo.token);
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index f61d1b9..451afa0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -159,6 +159,10 @@
 
     @Override
     public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
+        final SurfaceControl leash = mDisplayAreaTokenMap.get(displayAreaInfo.token);
+        if (leash != null) {
+            leash.release();
+        }
         mDisplayAreaTokenMap.remove(displayAreaInfo.token);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 22b0ccb..da88c2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -943,6 +943,7 @@
         mPipBoundsState.setBounds(new Rect());
         mPipUiEventLoggerLogger.setTaskInfo(null);
         mMainExecutor.executeDelayed(() -> mPipMenuController.detach(), 0);
+        mLeash = null;
 
         if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
             mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 046b1a2..c8ee010 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -486,7 +486,15 @@
     }
 
     RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
-        return reparentSplitTasksForAnimation(apps, false /*splitExpectedToBeVisible*/);
+        try {
+            return reparentSplitTasksForAnimation(apps, false /*splitExpectedToBeVisible*/);
+        } finally {
+            for (RemoteAnimationTarget appTarget : apps) {
+                if (appTarget.leash != null) {
+                    appTarget.leash.release();
+                }
+            }
+        }
     }
 
     private RemoteAnimationTarget[] reparentSplitTasksForAnimation(RemoteAnimationTarget[] apps,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 55e7dac..70d728d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1024,6 +1024,7 @@
         }
 
         mRootTaskInfo = null;
+        mRootTaskLeash = null;
     }
 
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 99e7506..cb9e1a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -243,6 +243,7 @@
         if (mRootTaskInfo.taskId == taskId) {
             mCallbacks.onRootTaskVanished();
             mRootTaskInfo = null;
+            mRootLeash = null;
             mSyncQueue.runInSync(t -> {
                 t.remove(mDimLayer);
                 mSplitDecorManager.release(t);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index 2b6c0da..ce624f2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -51,7 +51,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Postsubmit
+@FlakyTest(bugId = 238367575)
 @Group3
 class AutoEnterPipOnGoToHomeTest(testSpec: FlickerTestParameter) : EnterPipTest(testSpec) {
     protected val taplInstrumentation = LauncherInstrumentation()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 0b53c40..4948158 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -46,6 +46,7 @@
 import android.os.RemoteException;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
+import android.view.SurfaceSession;
 import android.window.ITaskOrganizer;
 import android.window.ITaskOrganizerController;
 import android.window.TaskAppearedInfo;
@@ -137,13 +138,25 @@
     }
 
     @Test
-    public void registerOrganizer_sendRegisterTaskOrganizer() throws RemoteException {
+    public void testRegisterOrganizer_sendRegisterTaskOrganizer() throws RemoteException {
         mOrganizer.registerOrganizer();
 
         verify(mTaskOrganizerController).registerTaskOrganizer(any(ITaskOrganizer.class));
     }
 
     @Test
+    public void testTaskLeashReleasedAfterVanished() throws RemoteException {
+        RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+        SurfaceControl taskLeash = new SurfaceControl.Builder(new SurfaceSession())
+                .setName("task").build();
+        mOrganizer.registerOrganizer();
+        mOrganizer.onTaskAppeared(taskInfo, taskLeash);
+        assertTrue(taskLeash.isValid());
+        mOrganizer.onTaskVanished(taskInfo);
+        assertTrue(!taskLeash.isValid());
+    }
+
+    @Test
     public void testOneListenerPerType() {
         mOrganizer.addListenerForType(new TrackingTaskListener(), TASK_LISTENER_TYPE_MULTI_WINDOW);
         try {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ded9597..546f0c6 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1286,6 +1286,8 @@
         /**
          * Specifying if haptic should be muted or not when playing audio-haptic coupled data.
          * By default, haptic channels are disabled.
+         * <p>This will be ignored if the caller doesn't have the
+         * {@link android.Manifest.permission#VIBRATE} permission.
          * @param muted true to force muting haptic channels.
          * @return the same Builder instance.
          */
diff --git a/media/java/android/media/audiofx/HapticGenerator.java b/media/java/android/media/audiofx/HapticGenerator.java
index fe7f29e..d2523ef 100644
--- a/media/java/android/media/audiofx/HapticGenerator.java
+++ b/media/java/android/media/audiofx/HapticGenerator.java
@@ -91,7 +91,8 @@
     }
 
     /**
-     * Enable or disable the effect.
+     * Enable or disable the effect. The effect can only be enabled if the caller has the
+     * {@link android.Manifest.permission#VIBRATE} permission.
      *
      * @param enabled the requested enable state
      * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index db41601..a66dc77 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -427,18 +427,14 @@
                     mPipTransaction = null;
                 }
             }
-            // Release surface references now. This is apparently to free GPU
-            // memory while doing quick operations (eg. during CTS).
-            for (int i = 0; i < mLeashMap.size(); ++i) {
-                if (mLeashMap.keyAt(i) == mLeashMap.valueAt(i)) continue;
-                t.remove(mLeashMap.valueAt(i));
-            }
             try {
                 mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t);
             } catch (RemoteException e) {
                 Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
                 t.apply();
             }
+            // Only release the non-local created surface references. The animator is responsible
+            // for releasing the leashes created by local.
             for (int i = 0; i < mInfo.getChanges().size(); ++i) {
                 mInfo.getChanges().get(i).getLeash().release();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
index 4986fe8..99267e8 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
@@ -125,6 +125,13 @@
             // launched from behind the lock-screen.
             activityStarter.startActivity(intent, false /* dismissShade */)
         }
+
+        // Call this to make sure that the keyguard returns if the app that is being launched
+        // crashes after a timeout.
+        centralSurfaces.startLaunchTransitionTimeout()
+        // Call this to make sure the keyguard is ready to be dismissed once the next intent is
+        // handled by the OS (in our case it is the activity we started right above)
+        centralSurfaces.readyForKeyguardDone()
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 2fa104a..e73eaa1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -176,7 +176,7 @@
     // 1000 - dock
     public static final BooleanFlag SIMULATE_DOCK_THROUGH_CHARGING =
             new BooleanFlag(1000, true);
-    public static final BooleanFlag DOCK_SETUP_ENABLED = new BooleanFlag(1001, false);
+    public static final BooleanFlag DOCK_SETUP_ENABLED = new BooleanFlag(1001, true);
 
 
     // 1100 - windowing
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 2f732de..458ed40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -144,8 +144,7 @@
                     animatedFraction)
                 // When crossfading, let's keep the bounds at the right location during fading
                 boundsProgress = if (animationCrossFadeProgress < 0.5f) 0.0f else 1.0f
-                currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress,
-                    instantlyShowAtEnd = false)
+                currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress)
             } else {
                 // If we're not crossfading, let's interpolate from the start alpha to 1.0f
                 currentAlpha = MathUtils.lerp(animationStartAlpha, 1.0f, animatedFraction)
@@ -276,7 +275,7 @@
             if (value >= 0) {
                 updateTargetState()
                 // Setting the alpha directly, as the below call will use it to update the alpha
-                carouselAlpha = calculateAlphaFromCrossFade(field, instantlyShowAtEnd = true)
+                carouselAlpha = calculateAlphaFromCrossFade(field)
                 applyTargetStateIfNotAnimating()
             }
         }
@@ -414,18 +413,10 @@
      * @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching
      * between the start and the end location and the content is fully faded, while 0.75f means
      * that we're halfway faded in again in the target state.
-     *
-     * @param instantlyShowAtEnd should the view be instantly shown at the end. This is needed
-     * to avoid fadinging in when the target was hidden anyway.
      */
-    private fun calculateAlphaFromCrossFade(
-        crossFadeProgress: Float,
-        instantlyShowAtEnd: Boolean
-    ): Float {
+    private fun calculateAlphaFromCrossFade(crossFadeProgress: Float): Float {
         if (crossFadeProgress <= 0.5f) {
             return 1.0f - crossFadeProgress / 0.5f
-        } else if (instantlyShowAtEnd) {
-            return 1.0f
         } else {
             return (crossFadeProgress - 0.5f) / 0.5f
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 5f52485..281ef94 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -626,6 +626,7 @@
                     }
                 }, mainExecutor, bgExecutor);
 
+        mView.setBackgroundExecutor(bgExecutor);
         mView.setEdgeBackGestureHandler(mEdgeBackGestureHandler);
         mNavBarMode = mNavigationModeController.addListener(mModeChangedListener);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index ad3cfa3..b01dca1 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -88,6 +88,7 @@
 import java.io.PrintWriter;
 import java.util.Map;
 import java.util.Optional;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /** */
@@ -97,6 +98,8 @@
 
     final static boolean ALTERNATE_CAR_MODE_UI = false;
 
+    private Executor mBgExecutor;
+
     // The current view is one of mHorizontal or mVertical depending on the current configuration
     View mCurrentView = null;
     private View mVertical;
@@ -349,6 +352,10 @@
         notifyVerticalChangedListener(mIsVertical);
     }
 
+    public void setBackgroundExecutor(Executor bgExecutor) {
+        mBgExecutor = bgExecutor;
+    }
+
     public void setTouchHandler(Gefingerpoken touchHandler) {
         mTouchHandler = touchHandler;
     }
@@ -768,8 +775,8 @@
         updateSlippery();
         reloadNavIcons();
         updateNavButtonIcons();
-        WindowManagerWrapper.getInstance().setNavBarVirtualKeyHapticFeedbackEnabled(
-                !mShowSwipeUpUi);
+        mBgExecutor.execute(() -> WindowManagerWrapper.getInstance()
+                .setNavBarVirtualKeyHapticFeedbackEnabled(!mShowSwipeUpUi));
         getHomeButton().setAccessibilityDelegate(
                 mShowSwipeUpUi ? mQuickStepAccessibilityDelegate : null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index 8179d17..a833670 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -321,7 +321,10 @@
                 velocityTracker = null
             }
             MotionEvent.ACTION_CANCEL -> {
-                updateArrowState(GestureState.CANCELLED)
+                // Receiving a CANCEL implies that something else intercepted
+                // the gesture, i.e., the user did not cancel their gesture.
+                // Therefore, disappear immediately, with minimum fanfare.
+                updateArrowState(GestureState.GONE)
                 velocityTracker = null
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index fcafead..0697133 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -15,6 +15,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Interpolator;
 import android.view.animation.OvershootInterpolator;
@@ -626,6 +627,16 @@
         }
     }
 
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        if (mAdapter != null && mAdapter.getCount() > 0) {
+            event.setItemCount(mAdapter.getCount());
+            event.setFromIndex(getCurrentPageNumber());
+            event.setToIndex(getCurrentPageNumber());
+        }
+    }
+
     private static Animator setupBounceAnimator(View view, int ordinal) {
         view.setAlpha(0f);
         view.setScaleX(0f);
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index 09ed567..1b66932 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -175,12 +176,15 @@
                 mPermManager.revokeRuntimePermission(packageName, NOTIFICATION_PERMISSION,
                         userId, TAG);
             }
+            int flagMask = userSet || !grant
+                    ? FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT :
+                    FLAG_PERMISSION_USER_SET;
             if (userSet) {
                 mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION,
-                        FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, userId);
+                        flagMask, FLAG_PERMISSION_USER_SET, true, userId);
             } else {
                 mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION,
-                        0, FLAG_PERMISSION_USER_SET, true, userId);
+                        flagMask, 0, true, userId);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "Could not reach system server", e);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index d68cecb..89bb17f3 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -473,9 +473,13 @@
                 mApexManager.registerApkInApex(pkg);
             }
 
-            // Add the package's KeySets to the global KeySetManagerService
-            KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
-            ksms.addScannedPackageLPw(pkg);
+            // Don't add keysets for APEX as their package settings are not persisted and will
+            // result in orphaned keysets.
+            if ((scanFlags & SCAN_AS_APEX) == 0) {
+                // Add the package's KeySets to the global KeySetManagerService
+                KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+                ksms.addScannedPackageLPw(pkg);
+            }
 
             final Computer snapshot = mPm.snapshotComputer();
             mPm.mComponentResolver.addAllComponents(pkg, chatty, mPm.mSetupWizardPackage, snapshot);
@@ -3464,8 +3468,9 @@
         }
         // Sort the list to ensure we always process factory packages first
         Collections.sort(parseResults, (a, b) -> {
-            ApexInfo ai = parsingApexInfo.get(a.scanFile);
-            return ai.isFactory ? -1 : 1;
+            ApexInfo i1 = parsingApexInfo.get(a.scanFile);
+            ApexInfo i2 = parsingApexInfo.get(b.scanFile);
+            return Boolean.compare(i2.isFactory, i1.isFactory);
         });
 
 
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
new file mode 100644
index 0000000..181f5ad
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+/**
+ * The internal (in-process) system server API for the {@link
+ * com.android.server.timedetector.TimeDetectorService}.
+ *
+ * <p>The methods on this class can be called from any thread.
+ * @hide
+ */
+public interface TimeDetectorInternal {
+
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
new file mode 100644
index 0000000..1b47ebb
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Handler;
+
+import java.util.Objects;
+
+/**
+ * The real {@link TimeDetectorInternal} local service implementation.
+ *
+ * @hide
+ */
+public class TimeDetectorInternalImpl implements TimeDetectorInternal {
+
+    @NonNull private final Context mContext;
+    @NonNull private final Handler mHandler;
+    @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+
+    public TimeDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
+            @NonNull TimeDetectorStrategy timeDetectorStrategy) {
+        mContext = Objects.requireNonNull(context);
+        mHandler = Objects.requireNonNull(handler);
+        mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
+    }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 105cd78..02d3487 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -29,15 +29,18 @@
 import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.NetworkTimeSuggestion;
 import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timedetector.TimePoint;
 import android.content.Context;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ParcelableException;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
+import android.util.NtpTrustedTime;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -49,6 +52,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.time.DateTimeException;
 import java.util.Objects;
 
 /**
@@ -79,6 +83,11 @@
             TimeDetectorStrategy timeDetectorStrategy =
                     TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
 
+            // Create and publish the local service for use by internal callers.
+            TimeDetectorInternal internal =
+                    new TimeDetectorInternalImpl(context, handler, timeDetectorStrategy);
+            publishLocalService(TimeDetectorInternal.class, internal);
+
             TimeDetectorService service = new TimeDetectorService(
                     context, handler, serviceConfigAccessor, timeDetectorStrategy);
 
@@ -93,6 +102,7 @@
     @NonNull private final CallerIdentityInjector mCallerIdentityInjector;
     @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
     @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+    @NonNull private final NtpTrustedTime mNtpTrustedTime;
 
     /**
      * Holds the listeners. The key is the {@link IBinder} associated with the listener, the value
@@ -107,19 +117,21 @@
             @NonNull ServiceConfigAccessor serviceConfigAccessor,
             @NonNull TimeDetectorStrategy timeDetectorStrategy) {
         this(context, handler, serviceConfigAccessor, timeDetectorStrategy,
-                CallerIdentityInjector.REAL);
+                CallerIdentityInjector.REAL, NtpTrustedTime.getInstance(context));
     }
 
     @VisibleForTesting
     public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
             @NonNull ServiceConfigAccessor serviceConfigAccessor,
             @NonNull TimeDetectorStrategy timeDetectorStrategy,
-            @NonNull CallerIdentityInjector callerIdentityInjector) {
+            @NonNull CallerIdentityInjector callerIdentityInjector,
+            @NonNull NtpTrustedTime ntpTrustedTime) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
         mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
         mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
         mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
+        mNtpTrustedTime = Objects.requireNonNull(ntpTrustedTime);
 
         // Wire up a change listener so that ITimeZoneDetectorListeners can be notified when
         // the configuration changes for any reason.
@@ -308,6 +320,19 @@
     }
 
     @Override
+    public TimePoint latestNetworkTime() {
+        // TODO(b/222295093): Return the latest network time from mTimeDetectorStrategy once we can
+        //  be sure that all uses of NtpTrustedTime results in a suggestion being made to the time
+        //  detector. mNtpTrustedTime can be removed once this happens.
+        NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult();
+        if (ntpResult != null) {
+            return new TimePoint(ntpResult.getTimeMillis(), ntpResult.getElapsedRealtimeMillis());
+        } else {
+            throw new ParcelableException(new DateTimeException("Missing network time fix"));
+        }
+    }
+
+    @Override
     protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
             @Nullable String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c2b6b19..fa8ea76 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7733,9 +7733,6 @@
         // relatively fixed.
         overrideConfig.colorMode = fullConfig.colorMode;
         overrideConfig.densityDpi = fullConfig.densityDpi;
-        // The smallest screen width is the short side of screen bounds. Because the bounds
-        // and density won't be changed, smallestScreenWidthDp is also fixed.
-        overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
         if (info.isFixedOrientation()) {
             // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
             // apply runtime rotation changes.
@@ -7832,7 +7829,7 @@
             // computed accordingly.
             if (!matchParentBounds()) {
                 getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
-                        newParentConfiguration);
+                        newParentConfiguration, areBoundsLetterboxed());
             }
         // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
         // are already calculated in resolveFixedOrientationConfiguration.
@@ -8003,7 +8000,8 @@
         }
 
         // Since bounds has changed, the configuration needs to be computed accordingly.
-        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
+        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+                areBoundsLetterboxed());
     }
 
     void recomputeConfiguration() {
@@ -8219,7 +8217,7 @@
         // Calculate app bounds using fixed orientation bounds because they will be needed later
         // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
         getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
-                newParentConfig);
+                newParentConfig, mCompatDisplayInsets, areBoundsLetterboxed());
         mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
     }
 
@@ -8247,7 +8245,7 @@
             // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
             // restrict, the bounds should be the requested override bounds.
             getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
-                    getFixedRotationTransformDisplayInfo());
+                    getFixedRotationTransformDisplayInfo(), areBoundsLetterboxed());
         }
     }
 
@@ -8311,7 +8309,7 @@
         // are calculated in compat container space. The actual position on screen will be applied
         // later, so the calculation is simpler that doesn't need to involve offset from parent.
         getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
-                mCompatDisplayInsets);
+                mCompatDisplayInsets,  areBoundsLetterboxed());
         // Use current screen layout as source because the size of app is independent to parent.
         resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
                 getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d07cc68..9295c18 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -112,6 +112,7 @@
         RemoteAnimationTarget topAppTarget = null;
         int prevTaskId;
         int prevUserId;
+        boolean prepareAnimation;
 
         BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder();
         synchronized (wmService.mGlobalLock) {
@@ -257,7 +258,8 @@
                     BackNavigationInfo.typeToString(backType));
 
             // For now, we only animate when going home.
-            boolean prepareAnimation = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+            prepareAnimation = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+                    && requestAnimation
                     // Only create a new leash if no leash has been created.
                     // Otherwise return null for animation target to avoid conflict.
                     && !removedWindowContainer.hasCommittedReparentToAnimationLeash();
@@ -292,7 +294,7 @@
             }
 
             // Special handling for back to home animation
-            if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation
+            if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation
                     && prevTask != null) {
                 currentTask.mBackGestureStarted = true;
                 // Make launcher show from behind by marking its top activity as visible and
@@ -347,7 +349,7 @@
             Task finalTask = currentTask;
             RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
                     result, finalRemovedWindowContainer, finalBackType, finalTask,
-                    finalprevActivity, requestAnimation));
+                    finalprevActivity, prepareAnimation));
             infoBuilder.setOnBackNavigationDone(onBackNavigationDone);
         }
 
@@ -381,14 +383,14 @@
 
     private void onBackNavigationDone(
             Bundle result, WindowContainer<?> windowContainer, int backType,
-            Task task, ActivityRecord prevActivity, boolean requestAnimation) {
+            Task task, ActivityRecord prevActivity, boolean prepareAnimation) {
         SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
         boolean triggerBack = result != null && result.getBoolean(
                 BackNavigationInfo.KEY_TRIGGER_BACK);
         ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
                 + "task=%s, prevActivity=%s", backType, task, prevActivity);
 
-        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation) {
+        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation) {
             if (triggerBack) {
                 if (surfaceControl != null && surfaceControl.isValid()) {
                     // When going back to home, hide the task surface before it is re-parented to
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3e6546e..23adee6 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1957,29 +1957,37 @@
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig) {
         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
-                null /* compatInsets */);
+                null /* compatInsets */, false /* areBoundsLetterboxed */);
     }
 
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
+            @NonNull Configuration parentConfig, boolean areBoundsLetterboxed) {
+        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
+                null /* compatInsets */, areBoundsLetterboxed);
+    }
+
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
+            boolean areBoundsLetterboxed) {
         if (overrideDisplayInfo != null) {
             // Make sure the screen related configs can be computed by the provided display info.
             inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
             invalidateAppBoundsConfig(inOutConfig);
         }
         computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
-                null /* compatInsets */);
+                null /* compatInsets */, areBoundsLetterboxed);
     }
 
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig,
-            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+            @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
+            boolean areBoundsLetterboxed) {
         if (compatInsets != null) {
             // Make sure the app bounds can be computed by the compat insets.
             invalidateAppBoundsConfig(inOutConfig);
         }
         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
-                compatInsets);
+                compatInsets, areBoundsLetterboxed);
     }
 
     /**
@@ -2006,7 +2014,8 @@
      **/
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
-            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+            @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
+            boolean areBoundsLetterboxed) {
         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
             windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2113,6 +2122,7 @@
                         : overrideScreenHeightDp;
             }
 
+            // TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp.
             if (inOutConfig.smallestScreenWidthDp
                     == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
                 // When entering to or exiting from Pip, the PipTaskOrganizer will set the
@@ -2128,9 +2138,10 @@
                     // task, because they should not be affected by insets.
                     inOutConfig.smallestScreenWidthDp = (int) (0.5f
                             + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
-                } else if (isEmbedded()) {
-                    // For embedded TFs, the smallest width should be updated. Otherwise, inherit
-                    // from the parent task would result in applications loaded wrong resource.
+                } else if (isEmbedded() || areBoundsLetterboxed || customContainerPolicy) {
+                    // For embedded TFs and activities that are letteboxed or eligible for size
+                    // compat mode, the smallest width should be updated. Otherwise, inherit from
+                    // the parent task would result in applications loaded wrong resource.
                     inOutConfig.smallestScreenWidthDp =
                             Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
                 }
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 27d181f..8b71a34 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -527,11 +527,12 @@
                 mService.mRootWindowContainer.forAllTasks((task) -> {
                     boolean returnTask = !task.mCreatedByOrganizer;
                     task.updateTaskOrganizerState(returnTask /* skipTaskAppeared */);
-                    if (returnTask) {
-                        SurfaceControl outSurfaceControl = state.addTaskWithoutCallback(task,
+                    // It is possible for the task to not yet have a surface control, so ensure that
+                    // the update succeeded in setting the organizer for the task before returning
+                    if (task.isOrganized() && returnTask) {
+                        SurfaceControl taskLeash = state.addTaskWithoutCallback(task,
                                 "TaskOrganizerController.registerTaskOrganizer");
-                        taskInfos.add(
-                                new TaskAppearedInfo(task.getTaskInfo(), outSurfaceControl));
+                        taskInfos.add(new TaskAppearedInfo(task.getTaskInfo(), taskLeash));
                     }
                 });
             };
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 24a478e..33b4982 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3756,6 +3756,15 @@
      * hierarchy change implies a configuration change.
      */
     private void onSyncReparent(WindowContainer oldParent, WindowContainer newParent) {
+        // Check if this is changing displays. If so, mark the old display as "ready" for
+        // transitions. This is to work around the problem where setting readiness against this
+        // container will only set the new display as ready and leave the old display as unready.
+        if (mSyncState != SYNC_STATE_NONE && oldParent != null
+                && oldParent.getDisplayContent() != null && (newParent == null
+                        || oldParent.getDisplayContent() != newParent.getDisplayContent())) {
+            mTransitionController.setReady(oldParent.getDisplayContent());
+        }
+
         if (newParent == null || newParent.mSyncState == SYNC_STATE_NONE) {
             if (mSyncState == SYNC_STATE_NONE) {
                 return;
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
index a6ed1ae..e724e804 100644
--- a/services/tests/apexsystemservices/Android.bp
+++ b/services/tests/apexsystemservices/Android.bp
@@ -39,6 +39,6 @@
     ],
     test_suites: [
         "device-tests",
-        "mts-core",
+        "mts-mainline-infra",
     ],
 }
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
new file mode 100644
index 0000000..d016d7e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.UserIdInt;
+import android.app.time.ExternalTimeSuggestion;
+import android.app.timedetector.GnssTimeSuggestion;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
+import android.util.IndentingPrintWriter;
+
+/**
+ * A fake implementation of {@link com.android.server.timedetector.TimeDetectorStrategy} for use
+ * in tests.
+ */
+class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
+
+    // Call tracking.
+    private TelephonyTimeSuggestion mLastTelephonySuggestion;
+    private @UserIdInt Integer mLastManualSuggestionUserId;
+    private ManualTimeSuggestion mLastManualSuggestion;
+    private NetworkTimeSuggestion mLastNetworkSuggestion;
+    private GnssTimeSuggestion mLastGnssSuggestion;
+    private ExternalTimeSuggestion mLastExternalSuggestion;
+    private boolean mDumpCalled;
+
+    @Override
+    public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
+        mLastTelephonySuggestion = timeSuggestion;
+    }
+
+    @Override
+    public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion timeSuggestion) {
+        mLastManualSuggestionUserId = userId;
+        mLastManualSuggestion = timeSuggestion;
+        return true;
+    }
+
+    @Override
+    public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
+        mLastNetworkSuggestion = timeSuggestion;
+    }
+
+    @Override
+    public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
+        mLastGnssSuggestion = timeSuggestion;
+    }
+
+    @Override
+    public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
+        mLastExternalSuggestion = timeSuggestion;
+    }
+
+    @Override
+    public void dump(IndentingPrintWriter pw, String[] args) {
+        mDumpCalled = true;
+    }
+
+    void resetCallTracking() {
+        mLastTelephonySuggestion = null;
+        mLastManualSuggestionUserId = null;
+        mLastManualSuggestion = null;
+        mLastNetworkSuggestion = null;
+        mLastGnssSuggestion = null;
+        mLastExternalSuggestion = null;
+        mDumpCalled = false;
+    }
+
+    void verifySuggestTelephonyTimeCalled(TelephonyTimeSuggestion expectedSuggestion) {
+        assertEquals(expectedSuggestion, mLastTelephonySuggestion);
+    }
+
+    void verifySuggestManualTimeCalled(
+            @UserIdInt int expectedUserId, ManualTimeSuggestion expectedSuggestion) {
+        assertEquals((Integer) expectedUserId, mLastManualSuggestionUserId);
+        assertEquals(expectedSuggestion, mLastManualSuggestion);
+    }
+
+    void verifySuggestNetworkTimeCalled(NetworkTimeSuggestion expectedSuggestion) {
+        assertEquals(expectedSuggestion, mLastNetworkSuggestion);
+    }
+
+    void verifySuggestGnssTimeCalled(GnssTimeSuggestion expectedSuggestion) {
+        assertEquals(expectedSuggestion, mLastGnssSuggestion);
+    }
+
+    void verifySuggestExternalTimeCalled(ExternalTimeSuggestion expectedSuggestion) {
+        assertEquals(expectedSuggestion, mLastExternalSuggestion);
+    }
+
+    void verifyDumpCalled() {
+        assertTrue(mDumpCalled);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
new file mode 100644
index 0000000..06512fb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.HandlerThread;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.timezonedetector.TestHandler;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class TimeDetectorInternalImplTest {
+
+    private Context mMockContext;
+    private FakeTimeDetectorStrategy mFakeTimeDetectorStrategy;
+
+    private TimeDetectorInternalImpl mTimeDetectorInternal;
+    private HandlerThread mHandlerThread;
+    private TestHandler mTestHandler;
+
+    @Before
+    public void setUp() {
+        mMockContext = mock(Context.class);
+
+        // Create a thread + handler for processing the work that the service posts.
+        mHandlerThread = new HandlerThread("TimeDetectorInternalTest");
+        mHandlerThread.start();
+        mTestHandler = new TestHandler(mHandlerThread.getLooper());
+
+        mFakeTimeDetectorStrategy = new FakeTimeDetectorStrategy();
+
+        mTimeDetectorInternal = new TimeDetectorInternalImpl(
+                mMockContext, mTestHandler, mFakeTimeDetectorStrategy);
+    }
+
+    @Test
+    public void placeholder() {
+      // A placeholder test until there are real methods to test.
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quit();
+        mHandlerThread.join();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index e9617e9..702ebeb 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -19,6 +19,7 @@
 import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
@@ -41,12 +42,14 @@
 import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.NetworkTimeSuggestion;
 import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timedetector.TimePoint;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.ParcelableException;
 import android.os.TimestampedValue;
-import android.util.IndentingPrintWriter;
+import android.util.NtpTrustedTime;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -77,7 +80,8 @@
     private TestHandler mTestHandler;
     private TestCallerIdentityInjector mTestCallerIdentityInjector;
     private FakeServiceConfigAccessor mFakeServiceConfigAccessor;
-    private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
+    private NtpTrustedTime mMockNtpTrustedTime;
+    private FakeTimeDetectorStrategy mFakeTimeDetectorStrategy;
 
 
     @Before
@@ -92,12 +96,13 @@
         mTestCallerIdentityInjector = new TestCallerIdentityInjector();
         mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
 
-        mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
+        mFakeTimeDetectorStrategy = new FakeTimeDetectorStrategy();
         mFakeServiceConfigAccessor = new FakeServiceConfigAccessor();
+        mMockNtpTrustedTime = mock(NtpTrustedTime.class);
 
         mTimeDetectorService = new TimeDetectorService(
                 mMockContext, mTestHandler, mFakeServiceConfigAccessor,
-                mStubbedTimeDetectorStrategy, mTestCallerIdentityInjector);
+                mFakeTimeDetectorStrategy, mTestCallerIdentityInjector, mMockNtpTrustedTime);
     }
 
     @After
@@ -275,7 +280,7 @@
                 anyString());
 
         mTestHandler.waitForMessagesToBeProcessed();
-        mStubbedTimeDetectorStrategy.verifySuggestTelephonyTimeCalled(timeSuggestion);
+        mFakeTimeDetectorStrategy.verifySuggestTelephonyTimeCalled(timeSuggestion);
     }
 
     @Test(expected = SecurityException.class)
@@ -301,7 +306,8 @@
         ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
 
         assertTrue(mTimeDetectorService.suggestManualTime(manualTimeSuggestion));
-        mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
+        mFakeTimeDetectorStrategy.verifySuggestManualTimeCalled(
+                mTestCallerIdentityInjector.getCallingUserId(), manualTimeSuggestion);
 
         verify(mMockContext).enforceCallingOrSelfPermission(
                 eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE),
@@ -336,7 +342,7 @@
                 eq(android.Manifest.permission.SET_TIME), anyString());
 
         mTestHandler.waitForMessagesToBeProcessed();
-        mStubbedTimeDetectorStrategy.verifySuggestNetworkTimeCalled(NetworkTimeSuggestion);
+        mFakeTimeDetectorStrategy.verifySuggestNetworkTimeCalled(NetworkTimeSuggestion);
     }
 
     @Test(expected = SecurityException.class)
@@ -366,7 +372,7 @@
                 eq(android.Manifest.permission.SET_TIME), anyString());
 
         mTestHandler.waitForMessagesToBeProcessed();
-        mStubbedTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
+        mFakeTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
     }
 
     @Test(expected = SecurityException.class)
@@ -396,7 +402,24 @@
                 eq(android.Manifest.permission.SUGGEST_EXTERNAL_TIME), anyString());
 
         mTestHandler.waitForMessagesToBeProcessed();
-        mStubbedTimeDetectorStrategy.verifySuggestExternalTimeCalled(externalTimeSuggestion);
+        mFakeTimeDetectorStrategy.verifySuggestExternalTimeCalled(externalTimeSuggestion);
+    }
+
+    @Test
+    public void testLatestNetworkTime() {
+        NtpTrustedTime.TimeResult latestNetworkTime =
+                new NtpTrustedTime.TimeResult(1234L, 54321L, 999L);
+        when(mMockNtpTrustedTime.getCachedTimeResult())
+                .thenReturn(latestNetworkTime);
+        TimePoint expected = new TimePoint(latestNetworkTime.getTimeMillis(),
+                latestNetworkTime.getElapsedRealtimeMillis());
+        assertEquals(expected, mTimeDetectorService.latestNetworkTime());
+    }
+
+    @Test
+    public void testLatestNetworkTime_noTimeAvailable() {
+        when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
+        assertThrows(ParcelableException.class, () -> mTimeDetectorService.latestNetworkTime());
     }
 
     @Test
@@ -408,7 +431,7 @@
         mTimeDetectorService.dump(null, pw, null);
 
         verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
-        mStubbedTimeDetectorStrategy.verifyDumpCalled();
+        mFakeTimeDetectorStrategy.verifyDumpCalled();
     }
 
     private static TimeConfiguration createTimeConfiguration(boolean autoDetectionEnabled) {
@@ -455,79 +478,4 @@
     private static ExternalTimeSuggestion createExternalTimeSuggestion() {
         return new ExternalTimeSuggestion(100L, 1_000_000L);
     }
-
-    private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
-
-        // Call tracking.
-        private TelephonyTimeSuggestion mLastTelephonySuggestion;
-        private ManualTimeSuggestion mLastManualSuggestion;
-        private NetworkTimeSuggestion mLastNetworkSuggestion;
-        private GnssTimeSuggestion mLastGnssSuggestion;
-        private ExternalTimeSuggestion mLastExternalSuggestion;
-        private boolean mDumpCalled;
-
-        @Override
-        public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
-            mLastTelephonySuggestion = timeSuggestion;
-        }
-
-        @Override
-        public boolean suggestManualTime(int userId, ManualTimeSuggestion timeSuggestion) {
-            mLastManualSuggestion = timeSuggestion;
-            return true;
-        }
-
-        @Override
-        public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
-            mLastNetworkSuggestion = timeSuggestion;
-        }
-
-        @Override
-        public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
-            mLastGnssSuggestion = timeSuggestion;
-        }
-
-        @Override
-        public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
-            mLastExternalSuggestion = timeSuggestion;
-        }
-
-        @Override
-        public void dump(IndentingPrintWriter pw, String[] args) {
-            mDumpCalled = true;
-        }
-
-        void resetCallTracking() {
-            mLastTelephonySuggestion = null;
-            mLastManualSuggestion = null;
-            mLastNetworkSuggestion = null;
-            mLastGnssSuggestion = null;
-            mLastExternalSuggestion = null;
-            mDumpCalled = false;
-        }
-
-        void verifySuggestTelephonyTimeCalled(TelephonyTimeSuggestion expectedSuggestion) {
-            assertEquals(expectedSuggestion, mLastTelephonySuggestion);
-        }
-
-        void verifySuggestManualTimeCalled(ManualTimeSuggestion expectedSuggestion) {
-            assertEquals(expectedSuggestion, mLastManualSuggestion);
-        }
-
-        void verifySuggestNetworkTimeCalled(NetworkTimeSuggestion expectedSuggestion) {
-            assertEquals(expectedSuggestion, mLastNetworkSuggestion);
-        }
-
-        void verifySuggestGnssTimeCalled(GnssTimeSuggestion expectedSuggestion) {
-            assertEquals(expectedSuggestion, mLastGnssSuggestion);
-        }
-
-        void verifySuggestExternalTimeCalled(ExternalTimeSuggestion expectedSuggestion) {
-            assertEquals(expectedSuggestion, mLastExternalSuggestion);
-        }
-
-        void verifyDumpCalled() {
-            assertTrue(mDumpCalled);
-        }
-    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 4c7e843..d4886e4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -183,7 +183,8 @@
         verify(mPermManager).grantRuntimePermission(
                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
-                FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
+                FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+                FLAG_PERMISSION_USER_SET, true, 10);
     }
 
     @Test
@@ -201,7 +202,8 @@
         verify(mPermManager).grantRuntimePermission(
                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
-                FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
+                FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+                FLAG_PERMISSION_USER_SET, true, 10);
     }
 
     @Test
@@ -214,7 +216,8 @@
         verify(mPermManager).revokeRuntimePermission(
                 eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
-                FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
+                FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+                FLAG_PERMISSION_USER_SET, true, 10);
     }
 
     @Test
@@ -227,7 +230,7 @@
         verify(mPermManager).grantRuntimePermission(
                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
-                0, FLAG_PERMISSION_USER_SET, true, 10);
+                FLAG_PERMISSION_USER_SET, 0, true, 10);
     }
 
     @Test
@@ -240,7 +243,8 @@
         verify(mPermManager).revokeRuntimePermission(
                 eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
-                0, FLAG_PERMISSION_USER_SET, true, 10);
+                FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0,
+                true, 10);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 324e244..f2640d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1496,6 +1496,79 @@
     }
 
     @Test
+    public void testComputeConfigResourceOverrides_unresizableApp() {
+        // Set up a display in landscape and ignoring orientation request.
+        setUpDisplaySizeWithApp(2800, 1400);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+        final Rect activityBounds = new Rect(mActivity.getBounds());
+
+        int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
+        int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
+
+        // App should launch in fixed orientation letterbox.
+        // Activity bounds should be 700x1400 with the ratio as the display.
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+        assertFitted();
+        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+        assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
+
+        // Rotate display to portrait.
+        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+        // After we rotate, the activity should go in the size-compat mode and report the same
+        // configuration values.
+        assertScaled();
+        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+        assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+
+        // Restart activity
+        mActivity.restartProcessIfVisible();
+
+        // Now configuration should be updated
+        assertFitted();
+        assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+        assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+        assertEquals(mActivity.getConfiguration().screenWidthDp,
+                mActivity.getConfiguration().smallestScreenWidthDp);
+    }
+
+    @Test
+    public void testComputeConfigResourceOverrides_resizableFixedOrientationActivity() {
+        // Set up a display in landscape and ignoring orientation request.
+        setUpDisplaySizeWithApp(2800, 1400);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        // Portrait fixed app without max aspect.
+        prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */);
+
+        final Rect activityBounds = new Rect(mActivity.getBounds());
+
+        int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
+        int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
+
+        // App should launch in fixed orientation letterbox.
+        // Activity bounds should be 700x1400 with the ratio as the display.
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+        assertFitted();
+        assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+        assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
+
+        // Rotate display to portrait.
+        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+        // Now configuration should be updated
+        assertFitted();
+        assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+        assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+        assertEquals(mActivity.getConfiguration().screenWidthDp,
+                mActivity.getConfiguration().smallestScreenWidthDp);
+    }
+
+    @Test
     public void testSplitAspectRatioForUnresizablePortraitApps() {
         // Set up a display in landscape and ignoring orientation request.
         int screenWidth = 1600;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 46e21f1..e2fe1b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -691,7 +691,8 @@
         final ActivityRecord.CompatDisplayInsets compatInsets =
                 new ActivityRecord.CompatDisplayInsets(
                         display, activity, /* fixedOrientationBounds= */ null);
-        task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
+        task.computeConfigResourceOverrides(
+                inOutConfig, parentConfig, compatInsets, /* areBoundsLetterboxed */ true);
 
         assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
         final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 9c2aac0..5407412 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -459,6 +459,23 @@
     }
 
     @Test
+    public void testRegisterTaskOrganizerWithExistingTasks_noSurfaceControl()
+            throws RemoteException {
+        final Task rootTask = createRootTask();
+        final Task task = createTask(rootTask);
+        final Task rootTask2 = createRootTask();
+        final Task task2 = createTask(rootTask2);
+        rootTask2.setSurfaceControl(null);
+        ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
+        final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
+        assertContainsTasks(existingTasks, rootTask);
+
+        // Verify we don't get onTaskAppeared if we are returned the tasks
+        verify(organizer, never())
+                .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
+    }
+
+    @Test
     public void testTaskTransaction() {
         removeGlobalMinSizeRestriction();
         final Task rootTask = new TaskBuilder(mSupervisor)
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 7731e09..855d3c1 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -46,6 +46,7 @@
         "launcher-helper-lib",
         "launcher-aosp-tapl",
         "platform-test-annotations",
+        "wm-flicker-window-extensions",
     ],
 }
 
@@ -83,5 +84,21 @@
         "flickertestapplib",
         "truth-prebuilt",
         "app-helpers-core",
+        "wm-flicker-window-extensions",
     ],
 }
+
+android_library_import {
+    name: "wm-flicker-window-extensions_nodeps",
+    aars: ["libs/window-extensions-release.aar"],
+    sdk_version: "current",
+}
+
+java_library {
+    name: "wm-flicker-window-extensions",
+    sdk_version: "current",
+    static_libs: [
+        "wm-flicker-window-extensions_nodeps",
+    ],
+    installable: false,
+}
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml
index fda6091..e173eba0 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/AndroidManifest.xml
@@ -43,6 +43,7 @@
     <!-- Allow the test to write directly to /sdcard/ -->
     <application android:requestLegacyExternalStorage="true">
         <uses-library android:name="android.test.runner"/>
+        <uses-library android:name="androidx.window.extensions" android:required="false"/>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/FlickerTests/libs/window-extensions-release.aar b/tests/FlickerTests/libs/window-extensions-release.aar
new file mode 100644
index 0000000..6fc9a67
--- /dev/null
+++ b/tests/FlickerTests/libs/window-extensions-release.aar
Binary files differ
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
new file mode 100644
index 0000000..ed411b5
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.app.Instrumentation
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.Before
+
+abstract class ActivityEmbeddingTestBase {
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val testApp = ActivityEmbeddingAppHelper(instrumentation)
+
+    @Before
+    fun assumeActivityEmbeddingSupported() {
+        // The test should only be run on devices that support ActivityEmbedding.
+        ActivityEmbeddingAppHelper.assumeActivityEmbeddingSupportedDevice()
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
new file mode 100644
index 0000000..28a72f4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test opening an activity that will launch another activity as ActivityEmbedding placeholder in
+ * split.
+ *
+ * To run this test: `atest FlickerTests:OpenActivityEmbeddingPlaceholderSplit`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenActivityEmbeddingPlaceholderSplit(private val testSpec: FlickerTestParameter) :
+    ActivityEmbeddingTestBase() {
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            setup {
+                eachRun {
+                    testApp.launchViaIntent(wmHelper)
+                }
+            }
+            transitions {
+                testApp.launchPlaceholderSplit(wmHelper)
+            }
+            teardown {
+                test {
+                    device.pressHome()
+                    testApp.exit(wmHelper)
+                }
+            }
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun mainActivityBecomesInvisible() {
+        testSpec.assertLayers {
+            isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+                    .then()
+                    .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun placeholderSplitBecomesVisible() {
+        testSpec.assertLayers {
+            isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+                    .then()
+                    .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+        }
+        testSpec.assertLayers {
+            isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+                    .then()
+                    .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+        }
+    }
+
+    companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(
+                            repetitions = 1,
+                            supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
+                            supportedNavigationModes = listOf(
+                                    WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+                                    WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                            )
+                    )
+        }
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
new file mode 100644
index 0000000..a01f633
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.util.Log
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import androidx.window.extensions.WindowExtensions
+import androidx.window.extensions.WindowExtensionsProvider
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.windowmanager.WindowManagerState.Companion.STATE_RESUMED
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.Assume.assumeNotNull
+
+class ActivityEmbeddingAppHelper @JvmOverloads constructor(
+        instr: Instrumentation,
+        launcherName: String = ActivityOptions.ACTIVITY_EMBEDDING_LAUNCHER_NAME,
+        component: FlickerComponentName = MAIN_ACTIVITY_COMPONENT,
+        launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+                .getInstance(instr)
+                .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+    /**
+     * Clicks the button to launch the placeholder primary activity, which should launch the
+     * placeholder secondary activity based on the placeholder rule.
+     */
+    fun launchPlaceholderSplit(wmHelper: WindowManagerStateHelper) {
+        val launchButton = uiDevice.wait(
+                Until.findObject(By.res(getPackage(), "launch_placeholder_split_button")),
+                FIND_TIMEOUT)
+        require(launchButton != null) {
+            "Can't find launch placeholder split button on screen."
+        }
+        launchButton.click()
+        wmHelper.StateSyncBuilder()
+            .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, STATE_RESUMED)
+            .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, STATE_RESUMED)
+            .waitForAndVerify()
+    }
+
+    companion object {
+        private const val TAG = "ActivityEmbeddingAppHelper"
+
+        val MAIN_ACTIVITY_COMPONENT = ActivityOptions
+                .ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+
+        val PLACEHOLDER_PRIMARY_COMPONENT = ActivityOptions
+                .ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+
+        val PLACEHOLDER_SECONDARY_COMPONENT = ActivityOptions
+                .ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME
+                .toFlickerComponent()
+
+        @JvmStatic
+        fun getWindowExtensions(): WindowExtensions? {
+            try {
+                return WindowExtensionsProvider.getWindowExtensions()
+            } catch (e: NoClassDefFoundError) {
+                Log.d(TAG, "Extension implementation not found")
+            } catch (e: UnsupportedOperationException) {
+                Log.d(TAG, "Stub Extension")
+            }
+            return null
+        }
+
+        @JvmStatic
+        fun getActivityEmbeddingComponent(): ActivityEmbeddingComponent? {
+            return getWindowExtensions()?.activityEmbeddingComponent
+        }
+
+        @JvmStatic
+        fun assumeActivityEmbeddingSupportedDevice() {
+            assumeNotNull(getActivityEmbeddingComponent())
+        }
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 78660c0..0c698ab 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -26,6 +26,11 @@
     srcs: ["**/*.java"],
     sdk_version: "current",
     test_suites: ["device-tests"],
+    static_libs: [
+        "androidx.test.ext.junit",
+        "wm-flicker-common-app-helpers",
+        "wm-flicker-window-extensions",
+    ],
 }
 
 java_library {
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 3e2130d..387f19b 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -15,12 +15,14 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-     package="com.android.server.wm.flicker.testapp">
+    package="com.android.server.wm.flicker.testapp">
 
     <uses-sdk android:minSdkVersion="29"
          android:targetSdkVersion="29"/>
     <application android:allowBackup="false"
          android:supportsRtl="true">
+        <uses-library android:name="androidx.window.extensions" android:required="false"/>
+
         <activity android:name=".SimpleActivity"
              android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
              android:theme="@style/CutoutShortEdges"
@@ -163,5 +165,33 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+
+        <activity
+            android:name=".ActivityEmbeddingMainActivity"
+            android:label="ActivityEmbedding Main"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+            android:theme="@style/CutoutShortEdges"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ActivityEmbeddingPlaceholderPrimaryActivity"
+            android:label="ActivityEmbedding Placeholder Primary"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+            android:theme="@style/CutoutShortEdges"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+            android:exported="false">
+        </activity>
+        <activity
+            android:name=".ActivityEmbeddingPlaceholderSecondaryActivity"
+            android:label="ActivityEmbedding Placeholder Secondary"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+            android:theme="@style/CutoutShortEdges"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+            android:exported="false"/>
     </application>
 </manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
new file mode 100644
index 0000000..3a02cad
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root_activity_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
new file mode 100644
index 0000000..19c81a8
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:background="@android:color/holo_orange_light">
+
+    <Button
+        android:id="@+id/launch_placeholder_split_button"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:layout_centerHorizontal="true"
+        android:onClick="launchPlaceholderSplit"
+        android:text="Launch Placeholder Split" />
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java
new file mode 100644
index 0000000..cd23e9f
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/** Base activity of ActivityEmbedding split activities. */
+public abstract class ActivityEmbeddingBaseActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_embedding_base_layout);
+        findViewById(R.id.root_activity_layout).setBackgroundColor(getBackgroundColor());
+    }
+
+    /** Sets different colors to visually distinguish split pairs. */
+    abstract int getBackgroundColor();
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
new file mode 100644
index 0000000..166e3ca
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.View;
+
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.EmbeddingRule;
+import androidx.window.extensions.embedding.SplitPlaceholderRule;
+
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
+
+import java.util.Set;
+
+/** Main activity of the ActivityEmbedding test app to launch other embedding activities. */
+public class ActivityEmbeddingMainActivity extends Activity {
+    private static final String TAG = "ActivityEmbeddingMainActivity";
+    private static final float DEFAULT_SPLIT_RATIO = 0.5f;
+
+    private ActivityEmbeddingComponent mEmbeddingComponent;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_embedding_main_layout);
+
+        initializeSplitRules();
+    }
+
+    /** R.id.launch_placeholder_split_button onClick */
+    public void launchPlaceholderSplit(View view) {
+        startActivity(new Intent().setComponent(
+                ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME));
+    }
+
+    private void initializeSplitRules() {
+        mEmbeddingComponent = ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
+        if (mEmbeddingComponent == null) {
+            // Embedding not supported
+            Log.d(TAG, "ActivityEmbedding is not supported on this device");
+            finish();
+            return;
+        }
+
+        mEmbeddingComponent.setEmbeddingRules(getSplitRules());
+    }
+
+    private Set<EmbeddingRule> getSplitRules() {
+        final Set<EmbeddingRule> rules = new ArraySet<>();
+
+        final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule.Builder(
+                new Intent().setComponent(
+                        ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME),
+                activity -> activity instanceof ActivityEmbeddingPlaceholderPrimaryActivity,
+                intent -> intent.getComponent().equals(
+                        ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME),
+                windowMetrics -> true)
+                .setSplitRatio(DEFAULT_SPLIT_RATIO)
+                .build();
+        rules.add(placeholderRule);
+        return rules;
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java
new file mode 100644
index 0000000..05c7a0b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.graphics.Color;
+
+/**
+ * Primary activity that will launch {@link ActivityEmbeddingPlaceholderSecondaryActivity} to split
+ * as placeholder based on the placeholder rule.
+ */
+public class ActivityEmbeddingPlaceholderPrimaryActivity extends ActivityEmbeddingBaseActivity {
+    @Override
+    int getBackgroundColor() {
+        return Color.BLUE;
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java
new file mode 100644
index 0000000..a9a51cd
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.graphics.Color;
+
+/**
+ * Activity to be used as the secondary placeholder activity to split with
+ * {@link ActivityEmbeddingPlaceholderPrimaryActivity}.
+ */
+public class ActivityEmbeddingPlaceholderSecondaryActivity extends ActivityEmbeddingBaseActivity {
+    @Override
+    int getBackgroundColor() {
+        return Color.GREEN;
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 6cda482..19fafb7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -87,4 +87,17 @@
     public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
             new ComponentName(FLICKER_APP_PACKAGE,
                     FLICKER_APP_PACKAGE + ".NotificationActivity");
+
+    public static final String ACTIVITY_EMBEDDING_LAUNCHER_NAME = "ActivityEmbeddingMainActivity";
+    public static final ComponentName ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE,
+                    FLICKER_APP_PACKAGE + ".ActivityEmbeddingMainActivity");
+    public static final ComponentName
+            ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
+                    FLICKER_APP_PACKAGE,
+            FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderPrimaryActivity");
+    public static final ComponentName
+            ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
+                    FLICKER_APP_PACKAGE,
+            FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
 }
diff --git a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
index 782439f..d133f6f 100644
--- a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
+++ b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
@@ -117,6 +117,7 @@
         testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_PTP);
         testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_MIDI);
         testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_RNDIS);
+        testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_NCM);
     }
 
     public void testSetCurrentFunctions_shouldMatched() {
@@ -125,5 +126,6 @@
         testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_PTP);
         testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_MIDI);
         testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_RNDIS);
+        testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_NCM);
     }
 }
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 861d221..86bcb72 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -182,6 +182,14 @@
 
     @SmallTest
     @Test
+    public void setFunctionsNcm() {
+        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+                UsbManager.FUNCTION_NCM));
+        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_NCM, 0);
+    }
+
+    @SmallTest
+    @Test
     public void setFunctionsNcmAndRndis() {
         final long rndisPlusNcm = UsbManager.FUNCTION_RNDIS | UsbManager.FUNCTION_NCM;