Merge "Wifi: Update to the WifiLock API documentation"
diff --git a/api/system-current.txt b/api/system-current.txt
index 921a6bf..866c138 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1198,7 +1198,7 @@
     method public int getUsageSource();
     method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
     method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
     method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String, long);
     method public void reportUsageStop(@NonNull android.app.Activity, @NonNull String);
@@ -5864,6 +5864,7 @@
     field public static final String NAMESPACE_DEX_BOOT = "dex_boot";
     field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
     field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
+    field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
     field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
@@ -5877,12 +5878,6 @@
     field public static final String SERVICE_ENABLED = "service_enabled";
   }
 
-  public static interface DeviceConfig.IntelligenceAttention {
-    field public static final String ATTENTION_ENABLED = "attention_enabled";
-    field public static final String ATTENTION_SETTINGS = "attention_settings";
-    field public static final String NAMESPACE = "intelligence_attention";
-  }
-
   public static interface DeviceConfig.OnPropertiesChangedListener {
     method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
   }
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 18d0ec0..2c65029 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -28,6 +28,14 @@
 
 }
 
+package android.app.usage {
+
+  public final class UsageStatsManager {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
+  }
+
+}
+
 package android.content {
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 2913743..a791d3f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -599,6 +599,7 @@
     method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
     method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
     field public static final String ROLLBACK_SERVICE = "rollback";
+    field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
   public class ContextWrapper extends android.content.Context {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 90bc0a6..6103818 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -104,11 +104,13 @@
 import android.net.IIpMemoryStore;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.ITestNetworkManager;
 import android.net.IpMemoryStore;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
 import android.net.NetworkWatchlistManager;
+import android.net.TestNetworkManager;
 import android.net.lowpan.ILowpanManager;
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
@@ -146,6 +148,7 @@
 import android.os.IncidentManager;
 import android.os.PowerManager;
 import android.os.RecoverySystem;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.SystemUpdateManager;
@@ -357,6 +360,29 @@
                 return new IpSecManager(ctx, service);
             }});
 
+        registerService(
+                Context.TEST_NETWORK_SERVICE,
+                TestNetworkManager.class,
+                new StaticApplicationContextServiceFetcher<TestNetworkManager>() {
+                    @Override
+                    public TestNetworkManager createService(Context context)
+                            throws ServiceNotFoundException {
+                        IBinder csBinder =
+                                ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
+                        IConnectivityManager csMgr =
+                                IConnectivityManager.Stub.asInterface(csBinder);
+
+                        final IBinder tnBinder;
+                        try {
+                            tnBinder = csMgr.startOrGetTestNetworkService();
+                        } catch (RemoteException e) {
+                            throw new ServiceNotFoundException(Context.TEST_NETWORK_SERVICE);
+                        }
+                        ITestNetworkManager tnMgr = ITestNetworkManager.Stub.asInterface(tnBinder);
+                        return new TestNetworkManager(context, tnMgr);
+                    }
+                });
+
         registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
                 new StaticServiceFetcher<CountryDetector>() {
             @Override
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index e47ec22..b5224c7 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -660,6 +660,30 @@
         }
     }
 
+
+    /**
+     * @deprecated use {@link #registerUsageSessionObserver(int, String[], Duration, Duration,
+     *                                                      PendingIntent, PendingIntent)}.
+     *
+     * @removed
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
+    // STOPSHIP b/128455269: remove this method
+    public void registerUsageSessionObserver(int sessionObserverId,
+            @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit,
+            long sessionThresholdTime,  @NonNull TimeUnit sessionThresholdTimeUnit,
+            @NonNull PendingIntent limitReachedCallbackIntent,
+            @Nullable PendingIntent sessionEndCallbackIntent) {
+        final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit));
+        final Duration sessionThresholdDuration =
+                Duration.ofMillis(sessionThresholdTimeUnit.toMillis(sessionThresholdTime));
+        registerUsageSessionObserver(sessionObserverId, observedEntities, timeLimitDuration,
+                sessionThresholdDuration, limitReachedCallbackIntent, sessionEndCallbackIntent);
+    }
+
     /**
      * Register a usage session observer that receives a callback on the provided {@code
      * limitReachedCallbackIntent} when the sum of usages of apps and tokens in the {@code
@@ -679,11 +703,8 @@
      *                         null and must include at least one package or token.
      * @param timeLimit The total time the set of apps can be used continuously before the {@code
      *                  limitReachedCallbackIntent} is delivered. Must be at least one minute.
-     * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
      * @param sessionThresholdTime The time that can take place between usage sessions before the
      *                             next session is considered a new session. Must be non-negative.
-     * @param sessionThresholdTimeUnit The unit for time specified in {@code sessionThreshold}.
-     *                                 Cannot be null.
      * @param limitReachedCallbackIntent The {@link PendingIntent} that will be dispatched when the
      *                                   usage limit is exceeded by the group of apps. The
      *                                   delivered Intent will also contain the extras {@link
@@ -703,14 +724,13 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
     public void registerUsageSessionObserver(int sessionObserverId,
-            @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit,
-            long sessionThresholdTime,  @NonNull TimeUnit sessionThresholdTimeUnit,
+            @NonNull String[] observedEntities, @NonNull Duration timeLimit,
+            @NonNull Duration sessionThresholdTime,
             @NonNull PendingIntent limitReachedCallbackIntent,
             @Nullable PendingIntent sessionEndCallbackIntent) {
         try {
             mService.registerUsageSessionObserver(sessionObserverId, observedEntities,
-                    timeUnit.toMillis(timeLimit),
-                    sessionThresholdTimeUnit.toMillis(sessionThresholdTime),
+                    timeLimit.toMillis(), sessionThresholdTime.toMillis(),
                     limitReachedCallbackIntent, sessionEndCallbackIntent,
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5c99319..efb3bfc1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3136,6 +3136,7 @@
             CONNECTIVITY_SERVICE,
             //@hide: IP_MEMORY_STORE_SERVICE,
             IPSEC_SERVICE,
+            TEST_NETWORK_SERVICE,
             //@hide: UPDATE_LOCK_SERVICE,
             //@hide: NETWORKMANAGEMENT_SERVICE,
             NETWORK_STATS_SERVICE,
@@ -3298,11 +3299,16 @@
      * {@link #USB_SERVICE}, {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE},
      * {@link #WIFI_SERVICE}, {@link #WIFI_AWARE_SERVICE}. For these services this method will
      * return <code>null</code>.  Generally, if you are running as an instant app you should always
-     * check whether the result of this method is null.
+     * check whether the result of this method is {@code null}.
+     *
+     * <p>Note: When implementing this method, keep in mind that new services can be added on newer
+     * Android releases, so if you're looking for just the explicit names mentioned above, make sure
+     * to return {@code null} when you don't recognize the name &mdash; if you throw a
+     * {@link RuntimeException} exception instead, you're app might break on new Android releases.
      *
      * @param name The name of the desired service.
      *
-     * @return The service or null if the name does not exist.
+     * @return The service or {@code null} if the name does not exist.
      *
      * @see #WINDOW_SERVICE
      * @see android.view.WindowManager
@@ -3376,7 +3382,9 @@
      * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
      * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
      * {@link android.app.usage.NetworkStatsManager}.
-     * </p><p>
+     * </p>
+     *
+     * <p>
      * Note: System services obtained via this API may be closely associated with
      * the Context in which they are obtained from.  In general, do not share the
      * service objects between various different contexts (Activities, Applications,
@@ -3388,11 +3396,13 @@
      * {@link #FINGERPRINT_SERVICE}, {@link #KEYGUARD_SERVICE}, {@link #SHORTCUT_SERVICE},
      * {@link #USB_SERVICE}, {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE},
      * {@link #WIFI_SERVICE}, {@link #WIFI_AWARE_SERVICE}. For these services this method will
-     * return <code>null</code>.  Generally, if you are running as an instant app you should always
-     * check whether the result of this method is null.
+     * return {@code null}. Generally, if you are running as an instant app you should always
+     * check whether the result of this method is {@code null}.
+     * </p>
      *
      * @param serviceClass The class of the desired service.
-     * @return The service or null if the class is not a supported system service.
+     * @return The service or {@code null} if the class is not a supported system service. Note:
+     * <b>never</b> throw a {@link RuntimeException} if the name is not supported.
      */
     @SuppressWarnings("unchecked")
     public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) {
@@ -3700,6 +3710,15 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
+     * android.net.TestNetworkManager} for building TUNs and limited-use Networks
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    @TestApi public static final String TEST_NETWORK_SERVICE = "test_network";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.os.IUpdateLock} for managing runtime sequences that
      * must not be interrupted by headless OTA application or similar.
      *
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
index b7ae8f4..d0657e5 100644
--- a/core/java/android/content/pm/AndroidHidlUpdater.java
+++ b/core/java/android/content/pm/AndroidHidlUpdater.java
@@ -34,8 +34,14 @@
 
     @Override
     public void updatePackage(Package pkg) {
+        ApplicationInfo info = pkg.applicationInfo;
+
         // This was the default <= P and is maintained for backwards compatibility.
-        if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.P) {
+        boolean isLegacy = info.targetSdkVersion <= Build.VERSION_CODES.P;
+        // Only system apps use these libraries
+        boolean isSystem = info.isSystemApp() || info.isUpdatedSystemApp();
+
+        if (isLegacy && isSystem) {
             prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
             prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
         } else {
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 0ef7656..b3cc627 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -22,6 +22,7 @@
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.PackageManager.ComponentInfoFlags;
 import android.content.pm.PackageManager.PackageInfoFlags;
@@ -925,4 +926,21 @@
      * @param provider the provider
      */
     public abstract void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider);
+
+    /**
+     * Returns {@code true} if given {@code packageName} is an apex package.
+     */
+    public abstract boolean isApexPackage(String packageName);
+
+    /**
+     * Uninstalls given {@code packageName}.
+     *
+     * @param packageName apex package to uninstall.
+     * @param versionCode version of a package to uninstall.
+     * @param userId user to uninstall apex package for. Must be
+     *               {@link android.os.UserHandle#USER_ALL}, otherwise failure will be reported.
+     * @param intentSender a {@link IntentSender} to send result of an uninstall to.
+     */
+    public abstract void uninstallApex(String packageName, long versionCode, int userId,
+            IntentSender intentSender);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ec42134..9d0ece0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3993,8 +3993,6 @@
         setMaxAspectRatio(owner);
         setMinAspectRatio(owner);
 
-        PackageBackwardCompatibility.modifySharedLibraries(owner);
-
         if (hasDomainURLs(owner)) {
             owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
         } else {
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 92653d18..a7ff644 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -1761,7 +1761,7 @@
         TunerCallbackAdapter halCallback = new TunerCallbackAdapter(callback, handler);
         try {
             tuner = mService.openTuner(moduleId, config, withAudio, halCallback);
-        } catch (RemoteException | IllegalArgumentException ex) {
+        } catch (RemoteException | IllegalArgumentException | IllegalStateException ex) {
             Log.e(TAG, "Failed to open tuner", ex);
             return null;
         }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 403b44d..f1e4f64 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -219,4 +219,6 @@
 
     void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
     void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
+
+    IBinder startOrGetTestNetworkService();
 }
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index e656466..32511e9 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -19,6 +19,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.UnsupportedAppUsage;
 import android.app.AlertDialog;
@@ -354,6 +355,7 @@
      * @return the DecorView for the current dialog window, if it exists.
      * If the window does not exist, null is returned.
      */
+    @Nullable
     private View getDecorView() {
         if (mDialog != null && mDialog.getWindow() != null) {
             return mDialog.getWindow().getDecorView();
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 7a0bb91..fd6a910 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -131,6 +131,14 @@
     public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
 
     /**
+     * Namespace for attention-based features provided by on-device machine intelligence.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
+
+    /**
      * Namespace for all media native related features.
      *
      * @hide
@@ -229,22 +237,6 @@
     }
 
     /**
-     * Namespace for attention-based features provided by on-device machine intelligence.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface IntelligenceAttention {
-        String NAMESPACE = "intelligence_attention";
-
-        /** If {@code true}, enables the attention features. */
-        String ATTENTION_ENABLED = "attention_enabled";
-
-        /** Settings for the attention features. */
-        String ATTENTION_SETTINGS = "attention_settings";
-    }
-
-    /**
      * Privacy related properties definitions.
      *
      * @hide
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 67d3629..8188e05 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -303,6 +303,47 @@
         return mText;
     }
 
+    /**
+     * Merges event of the same type, either {@link #TYPE_VIEW_TEXT_CHANGED}
+     * or {@link #TYPE_VIEW_DISAPPEARED}.
+     *
+     * @hide
+     */
+    public void mergeEvent(@NonNull ContentCaptureEvent event) {
+        Preconditions.checkNotNull(event);
+        final int eventType = event.getType();
+        if (mType != eventType) {
+            Log.e(TAG, "mergeEvent(" + getTypeAsString(eventType) + ") cannot be merged "
+                    + "with different eventType=" + getTypeAsString(mType));
+            return;
+        }
+
+        if (eventType == TYPE_VIEW_DISAPPEARED) {
+            final List<AutofillId> ids = event.getIds();
+            final AutofillId id = event.getId();
+            if (ids != null) {
+                if (id != null) {
+                    Log.w(TAG, "got TYPE_VIEW_DISAPPEARED event with both id and ids: " + event);
+                }
+                for (int i = 0; i < ids.size(); i++) {
+                    addAutofillId(ids.get(i));
+                }
+                return;
+            }
+            if (id != null) {
+                addAutofillId(id);
+                return;
+            }
+            throw new IllegalArgumentException("mergeEvent(): got "
+                    + "TYPE_VIEW_DISAPPEARED event with neither id or ids: " + event);
+        } else if (eventType == TYPE_VIEW_TEXT_CHANGED) {
+            setText(event.getText());
+        } else {
+            Log.e(TAG, "mergeEvent(" + getTypeAsString(eventType)
+                    + ") does not support this event type.");
+        }
+    }
+
     /** @hide */
     public void dump(@NonNull PrintWriter pw) {
         pw.print("type="); pw.print(getTypeAsString(mType));
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index dce8ebe..a2b12e0 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -295,8 +295,7 @@
                     Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text="
                             + getSanitizedString(event.getText()));
                 }
-                // TODO(b/124107816): should call lastEvent.merge(event) instead
-                lastEvent.setText(event.getText());
+                lastEvent.mergeEvent(event);
                 addEvent = false;
             }
         }
@@ -309,7 +308,7 @@
                     Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
                             + lastEvent.getSessionId());
                 }
-                mergeViewsDisappearedEvent(lastEvent, event);
+                lastEvent.mergeEvent(event);
                 addEvent = false;
             }
         }
@@ -357,30 +356,6 @@
         flush(flushReason);
     }
 
-    // TODO(b/124107816): should be ContentCaptureEvent Event.merge(event) instead (which would
-    // replace the addAutofillId() method - we would also need unit tests on ContentCaptureEventTest
-    // to check these scenarios)
-    private void mergeViewsDisappearedEvent(@NonNull ContentCaptureEvent lastEvent,
-            @NonNull ContentCaptureEvent event) {
-        final List<AutofillId> ids = event.getIds();
-        final AutofillId id = event.getId();
-        if (ids != null) {
-            if (id != null) {
-                Log.w(TAG, "got TYPE_VIEW_DISAPPEARED event with both id and ids: " + event);
-            }
-            for (int i = 0; i < ids.size(); i++) {
-                lastEvent.addAutofillId(ids.get(i));
-            }
-            return;
-        }
-        if (id != null) {
-            lastEvent.addAutofillId(id);
-            return;
-        }
-        throw new IllegalArgumentException(
-                "got TYPE_VIEW_DISAPPEARED event with neither id or ids: " + event);
-    }
-
     @UiThread
     private boolean hasStarted() {
         return mState != UNKNOWN_STATE;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 528a6a8..6d88530 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,7 +448,8 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
-                new WebViewDelegate().addWebViewAssetPath(initialApplication);
+                initialApplication.getAssets().addAssetPathAsSharedLibrary(
+                        webViewContext.getApplicationInfo().sourceDir);
                 ClassLoader clazzLoader = webViewContext.getClassLoader();
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 89e205c..8785251 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.DrawableRes;
+import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources.Theme;
@@ -44,6 +45,8 @@
 
 import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 
 /**
@@ -1259,9 +1262,20 @@
     }
 
     /**
+     * The valid input method modes for the {@link AutoCompleteTextView}:
+     *
+     * {@hide}
+     */
+    @IntDef({ListPopupWindow.INPUT_METHOD_FROM_FOCUSABLE,
+            ListPopupWindow.INPUT_METHOD_NEEDED,
+            ListPopupWindow.INPUT_METHOD_NOT_NEEDED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InputMethodMode {}
+
+    /**
      * Returns the input method mode used by the auto complete dropdown.
      */
-    public int getInputMethodMode() {
+    public @InputMethodMode int getInputMethodMode() {
         return mPopup.getInputMethodMode();
     }
 
@@ -1277,7 +1291,7 @@
      * {@link ListPopupWindow#INPUT_METHOD_NOT_NEEDED}. The auto-complete suggestions are always
      * displayed, even if the suggestions cover/hide the input method.
      */
-    public void setInputMethodMode(int mode) {
+    public void setInputMethodMode(@InputMethodMode int mode) {
         mPopup.setInputMethodMode(mode);
     }
 
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 2e709de..eb881de 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -614,6 +614,7 @@
                 if (remoteService != null) {
                     // TODO(b/117779333): we should probably ignore it if service is destroyed.
                     Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
+                    remoteService.finishRequest(this);
                     onTimeout(remoteService);
                 } else {
                     Slog.w(mTag, "timed out (no service)");
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 6a9db10..248e026 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -198,8 +198,8 @@
      *
      * <p>This function will crawl through all process {@code proc} directories found by the pattern
      * {@code /proc/[0-9]*}, and then check the UID using {@code /proc/$PID/status}. This takes
-     * approximately 500ms on a Pixel 2. Therefore, this method can be computationally expensive,
-     * and should not be called more than once an hour.
+     * approximately 500ms on a 2017 device. Therefore, this method can be computationally
+     * expensive, and should not be called more than once an hour.
      *
      * <p>Data is only collected for UIDs passing the predicate supplied in {@link
      * #setUidPredicate}.
@@ -283,7 +283,7 @@
                 if (threadCpuUsage == null) {
                     continue;
                 }
-                if (mMinimumTotalCpuUsageMillis < totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
+                if (mMinimumTotalCpuUsageMillis > totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
                     if (filteredThreadsCpuUsage == null) {
                         filteredThreadsCpuUsage = new int[mFrequenciesKhz.length];
                     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ea300aa..587d677 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -867,6 +867,7 @@
         android:label="@string/permgrouplab_visual"
         android:description="@string/permgroupdesc_visual"
         android:request="@string/permgrouprequest_visual"
+        android:requestDetail="@string/permgrouprequestdetail_visual"
         android:priority="920" />
 
     <!-- Allows an application to read the user's shared images collection. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bf7c8f2..bc66756 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -800,7 +800,9 @@
     <string name="permgroupdesc_visual">access your photos &amp; videos</string>
     <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
     <string name="permgrouprequest_visual">Allow
-        &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your photos and videos, including tagged locations?</string>
+        &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your photos and videos?</string>
+    <!-- Subtitle of the message shown to the user when the apps requests permission to access photos and videos [CHAR LIMIT=150]-->
+    <string name="permgrouprequestdetail_visual">Locations and other people in your photos and videos can be identified by the app</string>
 
     <!-- Title for the capability of an accessibility service to retrieve window content. -->
     <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
index 9b360db..cc48239 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -42,8 +42,17 @@
         PackageBuilder before = builder()
                 .targetSdkVersion(Build.VERSION_CODES.P);
 
+        // no change, not system
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void targeted_at_P_system() {
+        PackageBuilder before = builder().asSystemApp()
+                .targetSdkVersion(Build.VERSION_CODES.P);
+
         // Should add both HIDL libraries
-        PackageBuilder after = builder()
+        PackageBuilder after = builder().asSystemApp()
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
 
@@ -56,9 +65,19 @@
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(OTHER_LIBRARY);
 
+        // no change, not system
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void targeted_at_P_not_empty_usesLibraries_system() {
+        PackageBuilder before = builder().asSystemApp()
+                .targetSdkVersion(Build.VERSION_CODES.P)
+                .requiredLibraries(OTHER_LIBRARY);
+
         // The hidl jars should be added at the start of the list because it
         // is not on the bootclasspath and the package targets pre-P.
-        PackageBuilder after = builder()
+        PackageBuilder after = builder().asSystemApp()
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
 
@@ -71,8 +90,21 @@
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
 
-        // No change is required because although the HIDL libraries has been removed from
-        // the bootclasspath the package explicitly requests it.
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.P);
+
+        // Libraries are removed because they are not available for non-system apps
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_in_usesLibraries_system() {
+        PackageBuilder before = builder().asSystemApp()
+                .targetSdkVersion(Build.VERSION_CODES.P)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
         checkBackwardsCompatibility(before, before);
     }
 
@@ -83,8 +115,7 @@
         // Dependency is removed, it is not available.
         PackageBuilder after = builder();
 
-        // No change is required because the package explicitly requests the HIDL libraries
-        // and is targeted at the current version so does not need backwards compatibility.
+        // Libraries are removed because they are not available for apps targetting Q+
         checkBackwardsCompatibility(before, after);
     }
 
@@ -95,8 +126,7 @@
         // Dependency is removed, it is not available.
         PackageBuilder after = builder();
 
-        // No change is required because the package explicitly requests the HIDL libraries
-        // and is targeted at the current version so does not need backwards compatibility.
+        // Libraries are removed because they are not available for apps targetting Q+
         checkBackwardsCompatibility(before, after);
     }
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
index c5db962..f7544af 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
@@ -31,6 +31,8 @@
 
     private int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
 
+    private int mFlags = 0;
+
     private ArrayList<String> mRequiredLibraries;
 
     private ArrayList<String> mOptionalLibraries;
@@ -42,6 +44,7 @@
     public PackageParser.Package build() {
         PackageParser.Package pkg = new PackageParser.Package("org.package.name");
         pkg.applicationInfo.targetSdkVersion = mTargetSdkVersion;
+        pkg.applicationInfo.flags = mFlags;
         pkg.usesLibraries = mRequiredLibraries;
         pkg.usesOptionalLibraries = mOptionalLibraries;
         return pkg;
@@ -52,6 +55,11 @@
         return this;
     }
 
+    PackageBuilder asSystemApp() {
+        this.mFlags |= ApplicationInfo.FLAG_SYSTEM;
+        return this;
+    }
+
     PackageBuilder requiredLibraries(String... names) {
         this.mRequiredLibraries = arrayListOrNull(names);
         return this;
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
index de2edc3..2416de1 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
@@ -19,6 +19,7 @@
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -230,6 +231,68 @@
         assertContextUpdatedEvent(clone);
     }
 
+    @Test
+    public void testMergeEvent_typeViewTextChanged() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_TEXT_CHANGED)
+                .setText("test");
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_TEXT_CHANGED)
+                .setText("empty");
+
+        event.mergeEvent(event2);
+        assertThat(event.getText()).isEqualTo(event2.getText());
+    }
+
+    @Test
+    public void testMergeEvent_typeViewDisappeared() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+                .setAutofillId(new AutofillId(1));
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED)
+                .setAutofillId(new AutofillId(2));
+        final ArrayList<AutofillId> autofillIds = new ArrayList<>();
+        autofillIds.add(new AutofillId(3));
+        autofillIds.add(new AutofillId(4));
+        final ContentCaptureEvent event3 = new ContentCaptureEvent("17", TYPE_VIEW_DISAPPEARED)
+                .setAutofillIds(autofillIds);
+
+        event.mergeEvent(event2);
+        assertThat(event.getIds()).containsExactly(new AutofillId(1), new AutofillId(2));
+
+        event2.mergeEvent(event3);
+        assertThat(event2.getIds()).containsExactly(new AutofillId(2), new AutofillId(3),
+                new AutofillId(4));
+    }
+
+    @Test
+    public void testMergeEvent_typeViewDisappeared_noIds() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+                .setAutofillId(new AutofillId(1));
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED);
+
+        assertThrows(IllegalArgumentException.class, () -> event.mergeEvent(event2));
+    }
+
+    @Test
+    public void testMergeEvent_nullArgument() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        assertThrows(NullPointerException.class, () -> event.mergeEvent(null));
+    }
+
+    @Test
+    public void testMergeEvent_differentEventTypes() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+                .setText("test").setAutofillId(new AutofillId(1));
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("17", TYPE_VIEW_TEXT_CHANGED)
+                .setText("empty").setAutofillId(new AutofillId(2));
+
+        event.mergeEvent(event2);
+        assertThat(event.getText()).isEqualTo("test");
+        assertThat(event.getId()).isEqualTo(new AutofillId(1));
+
+        event2.mergeEvent(event);
+        assertThat(event2.getText()).isEqualTo("empty");
+        assertThat(event2.getId()).isEqualTo(new AutofillId(2));
+    }
+
     private void assertContextUpdatedEvent(ContentCaptureEvent event) {
         assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_UPDATED);
         assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 760f83b..6111110 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -70,8 +70,7 @@
  *         canvas.drawRect(...);
  *     } finally {
  *         renderNode.endRecording();
- *     }
- * </pre>
+ *     }</pre>
  *
  * <h3>Drawing a RenderNode in a View</h3>
  * <pre class="prettyprint">
@@ -84,8 +83,7 @@
  *             // Draw the RenderNode into this canvas.
  *             canvas.drawRenderNode(myRenderNode);
  *         }
- *     }
- * </pre>
+ *     }</pre>
  *
  * <h3>Releasing resources</h3>
  * <p>This step is not mandatory but recommended if you want to release resources
@@ -93,8 +91,7 @@
  * <pre class="prettyprint">
  *     // Discards the display list content allowing for any held resources to be released.
  *     // After calling this
- *     renderNode.discardDisplayList();
- * </pre>
+ *     renderNode.discardDisplayList();</pre>
  *
  *
  * <h3>Properties</h3>
@@ -132,8 +129,7 @@
  *          // will be invoked and will execute very quickly
  *          mRenderNode.offsetLeftAndRight(x);
  *          invalidate();
- *     }
- * </pre>
+ *     }</pre>
  *
  * <p>A few of the properties may at first appear redundant, such as {@link #setElevation(float)}
  * and {@link #setTranslationZ(float)}. The reason for these duplicates are to allow for a
@@ -146,24 +142,26 @@
  * overlap with {@link #setPosition(Rect)}.
  *
  * <p>The RenderNode's transform matrix is computed at render time as follows:
- * First a setTranslate(getTranslationX(), getTranslationY()) is applied to a {@link Matrix}.
- * Second a preRotate(getRotationZ(), getPivotX(), getPivotY()) is applied to the matrix. And
- * finally a preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY()) is applied. The current
- * canvas transform matrix, which is translated to the RenderNode's position,
- * is then multiplied by the RenderNode's transform matrix. Therefore there is no implicit
- * ordering in setting various RenderNode properties. That is to say that:
+ * <pre class="prettyprint">
+ *     Matrix transform = new Matrix();
+ *     transform.setTranslate(renderNode.getTranslationX(), renderNode.getTranslationY());
+ *     transform.preRotate(renderNode.getRotationZ(),
+ *             renderNode.getPivotX(), renderNode.getPivotY());
+ *     transform.preScale(renderNode.getScaleX(), renderNode.getScaleY(),
+ *             renderNode.getPivotX(), renderNode.getPivotY());</pre>
+ * The current canvas transform matrix, which is translated to the RenderNode's position,
+ * is then multiplied by the RenderNode's transform matrix. Therefore the ordering of calling
+ * property setters does not affect the result. That is to say that:
  *
  * <pre class="prettyprint">
  *     renderNode.setTranslationX(100);
- *     renderNode.setScaleX(100);
- * </pre>
+ *     renderNode.setScaleX(100);</pre>
  *
- * is equivalent to
+ * is equivalent to:
  *
  * <pre class="prettyprint">
  *     renderNode.setScaleX(100);
- *     renderNode.setTranslationX(100);
- * </pre>
+ *     renderNode.setTranslationX(100);</pre>
  *
  * <h3>Threading</h3>
  * <p>RenderNode may be created and used on any thread but they are not thread-safe. Only
@@ -182,8 +180,7 @@
  *         if (needsUpdate) {
  *             myOwningView.invalidate();
  *         }
- *     }
- * </pre>
+ *     }</pre>
  * This is marginally faster than doing a more explicit up-front check if the value changed by
  * comparing the desired value against {@link #getTranslationX()} as it minimizes JNI transitions.
  * The actual mechanism of requesting a new frame to be rendered will depend on how this
diff --git a/libs/hwui/tests/scripts/prep_generic.sh b/libs/hwui/tests/scripts/prep_generic.sh
new file mode 100755
index 0000000..223bf37
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_generic.sh
@@ -0,0 +1,249 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#################################################################
+###
+###  DO NOT MODIFY THIS FILE
+###  This is a copy of androidx's benchmark/lockClocks.sh
+###  Make changes there instead then copy here!
+###
+#################################################################
+
+# This script can be used to lock device clocks to stable levels for comparing
+# different versions of software.  Since the clock levels are not necessarily
+# indicative of real world behavior, this should **never** be used to compare
+# performance between different device models.
+
+# Fun notes for maintaining this file:
+#      `expr` can deal with ints > INT32_MAX, but if compares cannot. This is why we use MHz.
+#      `expr` can sometimes evaluate right-to-left. This is why we use parens.
+#      Everything below the initial host-check isn't bash - Android uses mksh
+#      mksh allows `\n` in an echo, bash doesn't
+#      can't use `awk`
+
+CPU_TARGET_FREQ_PERCENT=50
+GPU_TARGET_FREQ_PERCENT=50
+
+if [ "`command -v getprop`" == "" ]; then
+    if [ -n "`command -v adb`" ]; then
+        echo ""
+        echo "Pushing $0 and running it on device..."
+        dest=/data/local/tmp/`basename $0`
+        adb push $0 ${dest}
+        adb shell ${dest}
+        adb shell rm ${dest}
+        exit
+    else
+        echo "Could not find adb. Options are:"
+        echo "  1. Ensure adb is on your \$PATH"
+        echo "  2. Use './gradlew lockClocks'"
+        echo "  3. Manually adb push this script to your device, and run it there"
+        exit -1
+    fi
+fi
+
+# require root
+if [ "`id -u`" -ne "0" ]; then
+    echo "Not running as root, cannot lock clocks, aborting"
+    exit -1
+fi
+
+DEVICE=`getprop ro.product.device`
+MODEL=`getprop ro.product.model`
+
+# Find CPU max frequency, and lock big cores to an available frequency
+# that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores.
+function_lock_cpu() {
+    CPU_BASE=/sys/devices/system/cpu
+    GOV=cpufreq/scaling_governor
+
+    # Find max CPU freq, and associated list of available freqs
+    cpuMaxFreq=0
+    cpuAvailFreqCmpr=0
+    cpuAvailFreq=0
+    enableIndices=''
+    disableIndices=''
+    cpu=0
+    while [ -f ${CPU_BASE}/cpu${cpu}/online ]; do
+        # enable core, so we can find its frequencies
+        echo 1 > ${CPU_BASE}/cpu${cpu}/online
+
+        maxFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/cpuinfo_max_freq`
+        availFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/scaling_available_frequencies`
+        availFreqCmpr=${availFreq// /-}
+
+        if [ ${maxFreq} -gt ${cpuMaxFreq} ]; then
+            # new highest max freq, look for cpus with same max freq and same avail freq list
+            cpuMaxFreq=${maxFreq}
+            cpuAvailFreq=${availFreq}
+            cpuAvailFreqCmpr=${availFreqCmpr}
+
+            if [ -z ${disableIndices} ]; then
+                disableIndices="$enableIndices"
+            else
+                disableIndices="$disableIndices $enableIndices"
+            fi
+            enableIndices=${cpu}
+        elif [ ${maxFreq} == ${cpuMaxFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then
+            enableIndices="$enableIndices $cpu"
+        else
+            disableIndices="$disableIndices $cpu"
+        fi
+        cpu=$(($cpu + 1))
+    done
+
+    # Chose a frequency to lock to that's >= $CPU_TARGET_FREQ_PERCENT% of max
+    # (below, 100M = 1K for KHz->MHz * 100 for %)
+    TARGET_FREQ_MHZ=`expr \( ${cpuMaxFreq} \* ${CPU_TARGET_FREQ_PERCENT} \) \/ 100000`
+    chosenFreq=0
+    for freq in ${cpuAvailFreq}; do
+        freqMhz=`expr ${freq} \/ 1000`
+        if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ]; then
+            chosenFreq=${freq}
+            break
+        fi
+    done
+
+    # enable 'big' CPUs
+    for cpu in ${enableIndices}; do
+        freq=${CPU_BASE}/cpu$cpu/cpufreq
+
+        echo 1 > ${CPU_BASE}/cpu${cpu}/online
+        echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV}
+        echo ${chosenFreq} > ${freq}/scaling_max_freq
+        echo ${chosenFreq} > ${freq}/scaling_min_freq
+        echo ${chosenFreq} > ${freq}/scaling_setspeed
+
+        # validate setting the freq worked
+        obsCur=`cat ${freq}/scaling_cur_freq`
+        obsMin=`cat ${freq}/scaling_min_freq`
+        obsMax=`cat ${freq}/scaling_max_freq`
+        if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then
+            echo "Failed to set CPU$cpu to $chosenFreq Hz! Aborting..."
+            echo "scaling_cur_freq = $obsCur"
+            echo "scaling_min_freq = $obsMin"
+            echo "scaling_max_freq = $obsMax"
+            exit -1
+        fi
+    done
+
+    # disable other CPUs (Note: important to enable big cores first!)
+    for cpu in ${disableIndices}; do
+      echo 0 > ${CPU_BASE}/cpu${cpu}/online
+    done
+
+    echo "\nLocked CPUs ${enableIndices// /,} to $chosenFreq / $maxFreq KHz"
+    echo "Disabled CPUs ${disableIndices// /,}"
+}
+
+# If we have a Qualcomm GPU, find its max frequency, and lock to
+# an available frequency that's >= GPU_TARGET_FREQ_PERCENT% of max.
+function_lock_gpu_kgsl() {
+    if [ ! -d /sys/class/kgsl/kgsl-3d0/ ]; then
+        # not kgsl, abort
+        echo "\nCurrently don't support locking GPU clocks of $MODEL ($DEVICE)"
+        return -1
+    fi
+    if [ ${DEVICE} == "walleye" ] || [ ${DEVICE} == "taimen" ]; then
+        # Workaround crash
+        echo "\nUnable to lock GPU clocks of $MODEL ($DEVICE)"
+        return -1
+    fi
+
+    GPU_BASE=/sys/class/kgsl/kgsl-3d0
+
+    gpuMaxFreq=0
+    gpuAvailFreq=`cat $GPU_BASE/devfreq/available_frequencies`
+    for freq in ${gpuAvailFreq}; do
+        if [ ${freq} -gt ${gpuMaxFreq} ]; then
+            gpuMaxFreq=${freq}
+        fi
+    done
+
+    # (below, 100M = 1M for MHz * 100 for %)
+    TARGET_FREQ_MHZ=`expr \( ${gpuMaxFreq} \* ${GPU_TARGET_FREQ_PERCENT} \) \/ 100000000`
+
+    chosenFreq=${gpuMaxFreq}
+    index=0
+    chosenIndex=0
+    for freq in ${gpuAvailFreq}; do
+        freqMhz=`expr ${freq} \/ 1000000`
+        if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ] && [ ${chosenFreq} -ge ${freq} ]; then
+            # note avail freq are generally in reverse order, so we don't break out of this loop
+            chosenFreq=${freq}
+            chosenIndex=${index}
+        fi
+        index=$(($index + 1))
+    done
+    lastIndex=$(($index - 1))
+
+    firstFreq=`echo $gpuAvailFreq | cut -d" " -f1`
+
+    if [ ${gpuMaxFreq} != ${firstFreq} ]; then
+        # pwrlevel is index of desired freq among available frequencies, from highest to lowest.
+        # If gpuAvailFreq appears to be in-order, reverse the index
+        chosenIndex=$(($lastIndex - $chosenIndex))
+    fi
+
+    echo 0 > ${GPU_BASE}/bus_split
+    echo 1 > ${GPU_BASE}/force_clk_on
+    echo 10000 > ${GPU_BASE}/idle_timer
+
+    echo performance > ${GPU_BASE}/devfreq/governor
+
+    # NOTE: we store in min/max twice, because we don't know if we're increasing
+    # or decreasing, and it's invalid to try and set min > max, or max < min
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq
+    echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel
+    echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel
+    echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel
+    echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel
+
+    obsCur=`cat ${GPU_BASE}/devfreq/cur_freq`
+    obsMin=`cat ${GPU_BASE}/devfreq/min_freq`
+    obsMax=`cat ${GPU_BASE}/devfreq/max_freq`
+    if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then
+        echo "Failed to set GPU to $chosenFreq Hz! Aborting..."
+        echo "cur_freq = $obsCur"
+        echo "min_freq = $obsMin"
+        echo "max_freq = $obsMax"
+        echo "index = $chosenIndex"
+        exit -1
+    fi
+    echo "\nLocked GPU to $chosenFreq / $gpuMaxFreq Hz"
+}
+
+# kill processes that manage thermals / scaling
+stop thermal-engine
+stop perfd
+stop vendor.thermal-engine
+stop vendor.perfd
+
+function_lock_cpu
+
+function_lock_gpu_kgsl
+
+# Memory bus - hardcoded per-device for now
+if [ ${DEVICE} == "marlin" ] || [ ${DEVICE} == "sailfish" ]; then
+    echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/max_freq
+else
+    echo "\nUnable to lock memory bus of $MODEL ($DEVICE)."
+fi
+
+echo "\n$DEVICE clocks have been locked - to reset, reboot the device\n"
\ No newline at end of file
diff --git a/libs/hwui/tests/scripts/prep_ryu.sh b/libs/hwui/tests/scripts/prep_ryu.sh
old mode 100644
new mode 100755
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 8732524..45459fc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -161,6 +161,11 @@
         }
 
         buildNavBarContent();
+        // If the UI was rebuilt (day/night change) while the keyguard was up we need to
+        // correctly respect that state.
+        if (mIsKeyguard) {
+            updateNavBarForKeyguardContent();
+        }
     }
 
     private void addTemperatureViewToController(View v) {
@@ -211,6 +216,13 @@
     @Override
     public void showKeyguard() {
         super.showKeyguard();
+        updateNavBarForKeyguardContent();
+    }
+
+    /**
+     * Switch to the keyguard applicable content contained in the nav bars
+     */
+    private void updateNavBarForKeyguardContent() {
         getComponent(NotificationsUI.class).closeCarNotifications(0);
         if (mNavigationBarView != null) {
             mNavigationBarView.showKeyguardButtons();
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
index 8c6b9b0..5921868 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
@@ -64,4 +64,12 @@
         CarStatusBar statusBar = (CarStatusBar) mStatusBar;
         statusBar.showUserSwitcher();
     }
+
+    /**
+     * Do nothing on this change.
+     * The base class hides the keyguard which for automotive we want to avoid b/c this would happen
+     * on a configuration change due to day/night (headlight state).
+     */
+    @Override
+    public void onDensityOrFontScaleChanged() {  }
 }
diff --git a/packages/DynamicAndroidInstallationService/res/values/strings.xml b/packages/DynamicAndroidInstallationService/res/values/strings.xml
index aee67e1..03c7c28 100644
--- a/packages/DynamicAndroidInstallationService/res/values/strings.xml
+++ b/packages/DynamicAndroidInstallationService/res/values/strings.xml
@@ -30,6 +30,9 @@
     <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
     <string name="notification_action_reboot_to_dynandroid">Reboot</string>
 
-    <!-- Toast when installed AndroidOnTap is discarded [CHAR LIMIT=64] -->
+    <!-- Toast when installed DynamicAndroid is discarded [CHAR LIMIT=64] -->
     <string name="toast_dynandroid_discarded">Installed AndroidOnTap is discarded.</string>
+    <!-- Toast when we fail to launch into DynamicAndroid [CHAR LIMIT=64] -->
+    <string name="toast_failed_to_reboot_to_dynandroid">Failed to reboot into AndroidOnTap.</string>
+
 </resources>
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
index 63ac8c7..d942bab 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
@@ -278,10 +278,15 @@
         }
 
         if (!mInstallTask.commit()) {
-            // TODO: b/123673280 better UI response
             Log.e(TAG, "Failed to commit installation because of native runtime error.");
             mNM.cancel(NOTIFICATION_ID);
 
+            Toast.makeText(this,
+                    getString(R.string.toast_failed_to_reboot_to_dynandroid),
+                    Toast.LENGTH_LONG).show();
+
+            mDynAndroid.remove();
+
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 4da8ca2..9219594 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -107,6 +107,7 @@
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private @InteractionType int mInteractionFlags;
+    private boolean mBound;
     private boolean mIsEnabled;
     private int mCurrentBoundedUserId = -1;
     private float mBackButtonAlpha;
@@ -510,16 +511,15 @@
         mHandler.removeCallbacks(mConnectionRunnable);
         Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                 .setPackage(mRecentsComponentName.getPackageName());
-        boolean bound = false;
         try {
-            bound = mContext.bindServiceAsUser(launcherServiceIntent,
+            mBound = mContext.bindServiceAsUser(launcherServiceIntent,
                     mOverviewServiceConnection,
                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                     UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
         } catch (SecurityException e) {
             Log.e(TAG_OPS, "Unable to bind because of security error", e);
         }
-        if (bound) {
+        if (mBound) {
             // Ensure that connection has been established even if it thinks it is bound
             mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
         } else {
@@ -573,9 +573,14 @@
     }
 
     private void disconnectFromLauncherService() {
+        if (mBound) {
+            // Always unbind the service (ie. if called through onNullBinding or onBindingDied)
+            mContext.unbindService(mOverviewServiceConnection);
+            mBound = false;
+        }
+
         if (mOverviewProxy != null) {
             mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
-            mContext.unbindService(mOverviewServiceConnection);
             mOverviewProxy = null;
             notifyBackButtonAlphaChanged(1f, false /* animate */);
             notifyConnectionChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 60b1659..fc5cbeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -538,7 +538,7 @@
     private BatteryController mBatteryController;
     protected boolean mPanelExpanded;
     private UiModeManager mUiModeManager;
-    private boolean mIsKeyguard;
+    protected boolean mIsKeyguard;
     private LogMaker mStatusBarStateLog;
     protected NotificationIconAreaController mNotificationIconAreaController;
     @Nullable private View mAmbientIndicationContainer;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 72f7a68..3ed2948 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -299,6 +299,15 @@
     private INetworkPolicyManager mPolicyManager;
     private NetworkPolicyManagerInternal mPolicyManagerInternal;
 
+    /**
+     * TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple
+     * instances.
+     */
+    @GuardedBy("mTNSLock")
+    private TestNetworkService mTNS;
+
+    private final Object mTNSLock = new Object();
+
     private String mCurrentTcpBufferSizes;
 
     private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
@@ -6958,4 +6967,22 @@
             return vpn != null && vpn.getLockdown();
         }
     }
+
+    /**
+     * Returns a IBinder to a TestNetworkService. Will be lazily created as needed.
+     *
+     * <p>The TestNetworkService must be run in the system server due to TUN creation.
+     */
+    @Override
+    public IBinder startOrGetTestNetworkService() {
+        synchronized (mTNSLock) {
+            TestNetworkService.enforceTestNetworkPermissions(mContext);
+
+            if (mTNS == null) {
+                mTNS = new TestNetworkService(mContext, mNMS);
+            }
+
+            return mTNS;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 710a0ba3..3a50aa8 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -30,13 +30,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.BatteryManager;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
@@ -356,8 +354,8 @@
             try {
                 synchronized (mLock) {
                     if (mNightMode != mode) {
-                        // Only persist setting if not transient night mode or not in car mode
-                        if (!shouldTransientNightWhenInCarMode() || !mCarModeEnabled) {
+                        // Only persist setting if not in car mode
+                        if (!mCarModeEnabled) {
                             Settings.Secure.putIntForUser(getContext().getContentResolver(),
                                     Settings.Secure.UI_NIGHT_MODE, mode, user);
                         }
@@ -444,34 +442,12 @@
         }
     }
 
-    // Night mode settings in car mode are only persisted below Q.
-    // When targeting Q, changes are not saved and night mode will be re-read
-    // from settings when exiting car mode.
-    private boolean shouldTransientNightWhenInCarMode() {
-        int uid = Binder.getCallingUid();
-        PackageManager packageManager = getContext().getPackageManager();
-        String[] packagesForUid = packageManager.getPackagesForUid(uid);
-        if (packagesForUid == null || packagesForUid.length == 0) {
-            return false;
-        }
-
-        try {
-            ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
-                    packagesForUid[0], 0, uid);
-
-            return appInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
-        } catch (PackageManager.NameNotFoundException ignored) {
-        }
-
-        return false;
-    }
-
     void setCarModeLocked(boolean enabled, int flags) {
         if (mCarModeEnabled != enabled) {
             mCarModeEnabled = enabled;
 
-            // When transient night mode and exiting car mode, restore night mode from settings
-            if (shouldTransientNightWhenInCarMode() && !mCarModeEnabled) {
+            // When exiting car mode, restore night mode from settings
+            if (!mCarModeEnabled) {
                 Context context = getContext();
                 updateNightModeFromSettings(context,
                         context.getResources(),
@@ -534,9 +510,8 @@
             uiMode |= mNightMode << 4;
         }
 
-        // Override night mode in power save mode if not transient night mode or not in car mode
-        boolean shouldOverrideNight = !mCarModeEnabled || !shouldTransientNightWhenInCarMode();
-        if (mPowerSave && shouldOverrideNight) {
+        // Override night mode in power save mode if not in car mode
+        if (mPowerSave && !mCarModeEnabled) {
             uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
             uiMode |= Configuration.UI_MODE_NIGHT_YES;
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 57ce98c..cc90182 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -65,6 +65,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IProgressListener;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallback;
 import android.os.RemoteCallback.OnResultListener;
@@ -103,6 +104,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
@@ -114,6 +116,8 @@
     public static final String NO_CLASS_ERROR_CODE = "Error type 3";
     private static final String SHELL_PACKAGE_NAME = "com.android.shell";
 
+    private static final int USER_OPERATION_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
+
     // IPC interface to activity manager -- don't need to do additional security checks.
     final IActivityManager mInterface;
     final IActivityTaskManager mTaskInterface;
@@ -377,6 +381,30 @@
         });
     }
 
+    private class ProgressWaiter extends IProgressListener.Stub {
+        private final CountDownLatch mFinishedLatch = new CountDownLatch(1);
+
+        @Override
+        public void onStarted(int id, Bundle extras) {}
+
+        @Override
+        public void onProgress(int id, int progress, Bundle extras) {}
+
+        @Override
+        public void onFinished(int id, Bundle extras) {
+            mFinishedLatch.countDown();
+        }
+
+        public boolean waitForFinish(long timeoutMillis) {
+            try {
+                return mFinishedLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                System.err.println("Thread interrupted unexpectedly.");
+                return false;
+            }
+        }
+    }
+
     int runStartActivity(PrintWriter pw) throws RemoteException {
         Intent intent;
         try {
@@ -1692,8 +1720,24 @@
     }
 
     int runStartUser(PrintWriter pw) throws RemoteException {
-        String user = getNextArgRequired();
-        boolean success = mInterface.startUserInBackground(Integer.parseInt(user));
+        boolean wait = false;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if ("-w".equals(opt)) {
+                wait = true;
+            } else {
+                getErrPrintWriter().println("Error: unknown option: " + opt);
+                return -1;
+            }
+        }
+        int userId = Integer.parseInt(getNextArgRequired());
+
+        final ProgressWaiter waiter = wait ? new ProgressWaiter() : null;
+        boolean success = mInterface.startUserInBackgroundWithListener(userId, waiter);
+        if (wait && success) {
+            success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS);
+        }
+
         if (success) {
             pw.println("Success: user started");
         } else {
@@ -3023,9 +3067,10 @@
             pw.println("      execution of that user if it is currently stopped.");
             pw.println("  get-current-user");
             pw.println("      Returns id of the current foreground user.");
-            pw.println("  start-user <USER_ID>");
+            pw.println("  start-user [-w] <USER_ID>");
             pw.println("      Start USER_ID in background if it is currently stopped;");
-            pw.println("      use switch-user if you want to start the user in foreground");
+            pw.println("      use switch-user if you want to start the user in foreground.");
+            pw.println("      -w: wait for start-user to complete and the user to be unlocked.");
             pw.println("  unlock-user <USER_ID> [TOKEN_HEX]");
             pw.println("      Attempt to unlock the given user using the given authorization token.");
             pw.println("  stop-user [-w] [-f] <USER_ID>");
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 676cc33..f13c893 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -938,6 +938,7 @@
      *
      * @param userId ID of the user to start
      * @param foreground true if user should be brought to the foreground
+     * @param unlockListener Listener to be informed when the user has started and unlocked.
      * @return true if the user has been successfully started
      */
     boolean startUser(
@@ -962,6 +963,15 @@
         try {
             final int oldUserId = getCurrentUserId();
             if (oldUserId == userId) {
+                final UserState state = getStartedUserState(userId);
+                if (state != null && state.state == STATE_RUNNING_UNLOCKED) {
+                    // We'll skip all later code, so we must tell listener it's already unlocked.
+                    try {
+                        unlockListener.onFinished(userId, null);
+                    } catch (RemoteException ignore) {
+                        // Ignore.
+                    }
+                }
                 return true;
             }
 
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index a4c04b2..5fdd872 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -41,6 +41,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Function;
@@ -135,6 +136,17 @@
     }
 
     /**
+     * Checks if {@code packageName} is an apex package.
+     *
+     * @param packageName package to check.
+     * @return {@code true} if {@code packageName} is an apex package.
+     */
+    boolean isApexPackage(String packageName) {
+        populateActivePackagesCacheIfNeeded();
+        return mActivePackagesCache.containsKey(packageName);
+    }
+
+    /**
      * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
      * track the different states of a session.
      *
@@ -246,6 +258,23 @@
     }
 
     /**
+     * Uninstalls given {@code apexPackage}.
+     *
+     * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
+     *
+     * @param apexPackagePath package to uninstall.
+     * @return {@code true} upon successful uninstall, {@code false} otherwise.
+     */
+    boolean uninstallApex(String apexPackagePath) {
+        try {
+            mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
      * Dumps various state information to the provided {@link PrintWriter} object.
      *
      * @param pw the {@link PrintWriter} object to send information to.
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index cd0cbd6..af9b12a 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -17,7 +17,7 @@
 per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
 per-file BackgroundDexOptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
 per-file CompilerStats.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file DynamicCodeLoggingService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file DynamicCodeLoggingService.java = alanstokes@google.com, agampe@google.com, calin@google.com, ngeoffray@google.com
 per-file InstructionSets.java = agampe@google.com, calin@google.com, ngeoffray@google.com
 per-file OtaDexoptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
 per-file OtaDexoptShellCommand.java = agampe@google.com, calin@google.com, ngeoffray@google.com
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 3a4bcca..a7d70de 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -205,7 +205,7 @@
 
         mApexManager = am;
 
-        mStagingManager = new StagingManager(pm, this, am, context);
+        mStagingManager = new StagingManager(this, am, context);
     }
 
     boolean okToSendBroadcasts()  {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6f006e7..86dc734 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -160,6 +160,7 @@
 import android.content.pm.InstantAppRequest;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageBackwardCompatibility;
 import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
@@ -11058,6 +11059,8 @@
             pkg.mRealPackage = null;
             pkg.mAdoptPermissions = null;
         }
+
+        PackageBackwardCompatibility.modifySharedLibraries(pkg);
     }
 
     private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
@@ -23902,6 +23905,50 @@
                 mDefaultHomeProvider = provider;
             }
         }
+
+        @Override
+        public boolean isApexPackage(String packageName) {
+            return PackageManagerService.this.mApexManager.isApexPackage(packageName);
+        }
+
+        @Override
+        public void uninstallApex(String packageName, long versionCode, int userId,
+                IntentSender intentSender) {
+            final int callerUid = Binder.getCallingUid();
+            if (callerUid != Process.ROOT_UID && callerUid != Process.SHELL_UID) {
+                throw new SecurityException("Not allowed to uninstall apexes");
+            }
+            PackageInstallerService.PackageDeleteObserverAdapter adapter =
+                    new PackageInstallerService.PackageDeleteObserverAdapter(
+                            PackageManagerService.this.mContext, intentSender, packageName,
+                            false, userId);
+            if (userId != UserHandle.USER_ALL) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        "Can't uninstall an apex for a single user");
+                return;
+            }
+            final ApexManager am = PackageManagerService.this.mApexManager;
+            PackageInfo activePackage = am.getActivePackage(packageName);
+            if (activePackage == null) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        packageName + " is not an apex package");
+                return;
+            }
+            if (versionCode != PackageManager.VERSION_CODE_HIGHEST
+                    && activePackage.getLongVersionCode() != versionCode) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        "Active version " + activePackage.getLongVersionCode()
+                                + " is not equal to " + versionCode + "]");
+                return;
+            }
+            if (!am.uninstallApex(activePackage.applicationInfo.sourceDir)) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        "Failed to uninstall apex " + packageName);
+            } else {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_SUCCEEDED,
+                        null);
+            }
+        }
     }
 
     @GuardedBy("mPackages")
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 912a50e..2d1afa7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1619,30 +1619,36 @@
         }
 
         userId = translateUserId(userId, true /*allowAll*/, "runUninstall");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-            flags |= PackageManager.DELETE_ALL_USERS;
-        } else {
-            final PackageInfo info = mInterface.getPackageInfo(packageName,
-                    PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
-            if (info == null) {
-                pw.println("Failure [not installed for " + userId + "]");
-                return 1;
-            }
-            final boolean isSystem =
-                    (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-            // If we are being asked to delete a system app for just one
-            // user set flag so it disables rather than reverting to system
-            // version of the app.
-            if (isSystem) {
-                flags |= PackageManager.DELETE_SYSTEM_APP;
-            }
-        }
-
         final LocalIntentReceiver receiver = new LocalIntentReceiver();
-        mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
-                versionCode), null /*callerPackageName*/, flags,
-                receiver.getIntentSender(), userId);
+        PackageManagerInternal internal = LocalServices.getService(PackageManagerInternal.class);
+
+        if (internal.isApexPackage(packageName)) {
+            internal.uninstallApex(packageName, versionCode, userId, receiver.getIntentSender());
+        } else {
+            if (userId == UserHandle.USER_ALL) {
+                userId = UserHandle.USER_SYSTEM;
+                flags |= PackageManager.DELETE_ALL_USERS;
+            } else {
+                final PackageInfo info = mInterface.getPackageInfo(packageName,
+                        PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
+                if (info == null) {
+                    pw.println("Failure [not installed for " + userId + "]");
+                    return 1;
+                }
+                final boolean isSystem =
+                        (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+                // If we are being asked to delete a system app for just one
+                // user set flag so it disables rather than reverting to system
+                // version of the app.
+                if (isSystem) {
+                    flags |= PackageManager.DELETE_SYSTEM_APP;
+                }
+            }
+
+            mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
+                            versionCode), null /*callerPackageName*/, flags,
+                    receiver.getIntentSender(), userId);
+        }
 
         final Intent result = receiver.getResult();
         final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 088146d..ae75574 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -69,7 +69,6 @@
     private static final String TAG = "StagingManager";
 
     private final PackageInstallerService mPi;
-    private final PackageManagerService mPm;
     private final ApexManager mApexManager;
     private final PowerManager mPowerManager;
     private final Handler mBgHandler;
@@ -77,9 +76,7 @@
     @GuardedBy("mStagedSessions")
     private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
 
-    StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am,
-            Context context) {
-        mPm = pm;
+    StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
         mPi = pi;
         mApexManager = am;
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d58707c..2af2342 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -443,7 +443,7 @@
          * Returns true if the window is current in multi-windowing mode. i.e. it shares the
          * screen with other application windows.
          */
-        public boolean isInMultiWindowMode();
+        boolean inMultiWindowMode();
 
         public int getRotationAnimationHint();
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index bb5a221..af05a27 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -2237,6 +2237,10 @@
                 || transit == TRANSIT_ACTIVITY_RELAUNCH;
     }
 
+    static boolean isChangeTransit(int transit) {
+        return transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE;
+    }
+
     /**
      * @return whether the transition should show the thumbnail being scaled down.
      */
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 8f0a7c0..f6326957 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -513,8 +513,11 @@
         // Given no app transition pass it through instead of a wallpaper transition.
         // Never convert the crashing transition.
         // Never update the transition for the wallpaper if we are just docking from recents
+        // Never convert a change transition since the top activity isn't changing and will likely
+        // still be above an opening wallpaper.
         if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
-                || transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+                || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
+                || AppTransition.isChangeTransit(transit)) {
             return transit;
         }
 
@@ -601,6 +604,10 @@
      */
     @VisibleForTesting
     int maybeUpdateTransitToTranslucentAnim(int transit) {
+        if (AppTransition.isChangeTransit(transit)) {
+            // There's no special animation to handle change animations with translucent apps
+            return transit;
+        }
         final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
                 || AppTransition.isActivityTransit(transit);
         boolean allOpeningVisible = true;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 220370c..ea3a7d5 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1747,7 +1747,7 @@
     }
 
     boolean isInChangeTransition() {
-        return mTransitChangeLeash != null || isChangeTransition(mTransit);
+        return mTransitChangeLeash != null || AppTransition.isChangeTransit(mTransit);
     }
 
     @VisibleForTesting
@@ -1979,7 +1979,14 @@
                 mLetterbox.attachInput(w);
             }
             getPosition(mTmpPoint);
-            mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint);
+            // Get the bounds of the "space-to-fill". We union the Task and the Stack bounds here
+            // to handle both split window (where task-bounds can be larger) and orientation
+            // letterbox (where the task is letterboxed within stack).
+            Rect spaceToFill = getTask().getBounds();
+            if (getStack() != null) {
+                spaceToFill.union(getStack().getBounds());
+            }
+            mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
         } else if (mLetterbox != null) {
             mLetterbox.hide();
         }
@@ -2448,30 +2455,6 @@
         return boundsLayer;
     }
 
-    /** Get position and crop region of animation. */
-    @VisibleForTesting
-    void getAnimationBounds(Point outPosition, Rect outBounds) {
-        outPosition.set(0, 0);
-        outBounds.setEmpty();
-
-        final TaskStack stack = getStack();
-        final Task task = getTask();
-        if (task != null && task.inFreeformWindowingMode()) {
-            task.getRelativeDisplayedPosition(outPosition);
-        } else if (stack != null) {
-            stack.getRelativeDisplayedPosition(outPosition);
-        }
-
-        // Always use stack bounds in order to have the ability to animate outside the task region.
-        // It also needs to be consistent when {@link #mNeedsAnimationBoundsLayer} is set that crops
-        // according to the bounds.
-        if (stack != null) {
-            stack.getBounds(outBounds);
-        }
-        // We have the relative position so the local position can be removed from bounds.
-        outBounds.offsetTo(0, 0);
-    }
-
     @Override
     Rect getDisplayedBounds() {
         final Task task = getTask();
@@ -2484,10 +2467,6 @@
         return getBounds();
     }
 
-    private static boolean isChangeTransition(int transit) {
-        return transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE;
-    }
-
     boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
             boolean isVoiceInteraction) {
 
@@ -2507,9 +2486,15 @@
         if (okToAnimate()) {
             final AnimationAdapter adapter;
             AnimationAdapter thumbnailAdapter = null;
-            getAnimationBounds(mTmpPoint, mTmpRect);
 
-            boolean isChanging = isChangeTransition(transit) && enter;
+            // Separate position and size for use in animators. Use task-bounds for now so
+            // that activity-level letterbox (maxAspectRatio) is included in the animation.
+            mTmpRect.set(getTask() != null ? getTask().getBounds() : getBounds());
+            mTmpPoint.set(mTmpRect.left, mTmpRect.top);
+            mTmpRect.offsetTo(0, 0);
+
+            final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
+                    && getDisplayContent().mChangingApps.contains(this);
 
             // Delaying animation start isn't compatible with remote animations at all.
             if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e48361f..d3f6689 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2146,7 +2146,7 @@
         // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
         // Also, we don't allow windows in multi-window mode to extend out of the screen.
         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
-                && !win.isInMultiWindowMode()) {
+                && !win.inMultiWindowMode()) {
             df.left = df.top = -10000;
             df.right = df.bottom = 10000;
             if (type != TYPE_WALLPAPER) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 499cbaf..bb7867c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -433,29 +433,6 @@
         }
     }
 
-    /** Return true if the current bound can get outputted to the rest of the system as-is. */
-    private boolean useCurrentBounds() {
-        final DisplayContent displayContent = getDisplayContent();
-        return matchParentBounds()
-                || !inSplitScreenSecondaryWindowingMode()
-                || displayContent == null
-                || displayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null;
-    }
-
-    @Override
-    public void getBounds(Rect out) {
-        if (useCurrentBounds()) {
-            // No need to adjust the output bounds if fullscreen or the docked stack is visible
-            // since it is already what we want to represent to the rest of the system.
-            super.getBounds(out);
-            return;
-        }
-
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
-        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
-        mStack.getDisplayContent().getBounds(out);
-    }
-
     @Override
     public Rect getDisplayedBounds() {
         if (mOverrideDisplayedBounds.isEmpty()) {
@@ -506,36 +483,28 @@
         // a DimLayer anyway if we weren't visible.
         final boolean dockedResizing = displayContent != null
                 && displayContent.mDividerControllerLocked.isResizing();
-        if (useCurrentBounds()) {
-            if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
-                return;
-            }
-
-            if (!matchParentBounds()) {
-                // When minimizing the docked stack when going home, we don't adjust the task bounds
-                // so we need to intersect the task bounds with the stack bounds here.
-                //
-                // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
-                // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
-                // should keep up with the divider.
-                if (dockedResizing) {
-                    mStack.getBounds(out);
-                } else {
-                    mStack.getBounds(mTmpRect);
-                    mTmpRect.intersect(getBounds());
-                    out.set(mTmpRect);
-                }
-            } else {
-                out.set(getBounds());
-            }
+        if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
             return;
         }
 
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
-        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
-        if (displayContent != null) {
-            displayContent.getBounds(out);
+        if (!matchParentBounds()) {
+            // When minimizing the docked stack when going home, we don't adjust the task bounds
+            // so we need to intersect the task bounds with the stack bounds here.
+            //
+            // If we are Docked Resizing with snap points, the task bounds could be smaller than the
+            // stack bounds and so we don't even want to use them. Even if the app should not be
+            // resized the Dim should keep up with the divider.
+            if (dockedResizing) {
+                mStack.getBounds(out);
+            } else {
+                mStack.getBounds(mTmpRect);
+                mTmpRect.intersect(getBounds());
+                out.set(mTmpRect);
+            }
+        } else {
+            out.set(getBounds());
         }
+        return;
     }
 
     void setDragResizing(boolean dragResizing, int dragResizeMode) {
@@ -702,16 +671,6 @@
         positionChildAt(position, aToken, false /* includeParents */);
     }
 
-    boolean isFullscreen() {
-        if (useCurrentBounds()) {
-            return matchParentBounds();
-        }
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
-        // system.
-        return true;
-    }
-
     void forceWindowsScaleable(boolean force) {
         mWmService.openSurfaceTransaction();
         try {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 241f14e..e6b8112 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -303,17 +303,6 @@
         return super.getBounds();
     }
 
-    /** Return true if the current bound can get outputted to the rest of the system as-is. */
-    private boolean useCurrentBounds() {
-        if (matchParentBounds()
-                || !inSplitScreenSecondaryWindowingMode()
-                || mDisplayContent == null
-                || mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null) {
-            return true;
-        }
-        return false;
-    }
-
     @Override
     public void getBounds(Rect bounds) {
         bounds.set(getBounds());
@@ -321,22 +310,15 @@
 
     @Override
     public Rect getBounds() {
-        if (useCurrentBounds()) {
-            // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
-            // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
-            // stack is visible since it is already what we want to represent to the rest of the
-            // system.
-            if (!mAdjustedBounds.isEmpty()) {
-                return mAdjustedBounds;
-            } else {
-                return super.getBounds();
-            }
-        }
-
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+        // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
+        // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
+        // stack is visible since it is already what we want to represent to the rest of the
         // system.
-        return mDisplayContent.getBounds();
+        if (!mAdjustedBounds.isEmpty()) {
+            return mAdjustedBounds;
+        } else {
+            return super.getBounds();
+        }
     }
 
     /**
@@ -1425,13 +1407,7 @@
 
     @Override
     boolean fillsParent() {
-        if (useCurrentBounds()) {
-            return matchParentBounds();
-        }
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
-        // system.
-        return true;
+        return matchParentBounds();
     }
 
     @Override
@@ -1516,7 +1492,7 @@
 
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final Task task = mChildren.get(i);
-            if (task.isFullscreen()) {
+            if (task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                 results.searchDone = true;
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 20cca66..ee445d8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -826,7 +826,7 @@
         mHaveFrame = true;
 
         final Task task = getTask();
-        final boolean inFullscreenContainer = inFullscreenContainer();
+        final boolean isFullscreenAndFillsDisplay = !inMultiWindowMode() && matchesDisplayBounds();
         final boolean windowsAreFloating = task != null && task.isFloating();
         final DisplayContent dc = getDisplayContent();
 
@@ -845,7 +845,7 @@
         final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow();
         final boolean isImeTarget =
                 imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget();
-        if (inFullscreenContainer || layoutInParentFrame()) {
+        if (isFullscreenAndFillsDisplay || layoutInParentFrame()) {
             // We use the parent frame as the containing frame for fullscreen and child windows
             mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame);
             layoutDisplayFrame = mWindowFrames.mDisplayFrame;
@@ -983,7 +983,7 @@
                     Math.min(mWindowFrames.mStableFrame.bottom, mWindowFrames.mFrame.bottom));
         }
 
-        if (inFullscreenContainer && !windowsAreFloating) {
+        if (isFullscreenAndFillsDisplay && !windowsAreFloating) {
             // Windows that are not fullscreen can be positioned outside of the display frame,
             // but that is not a reason to provide them with overscan insets.
             InsetUtils.insetsBetweenFrames(layoutContainingFrame, mWindowFrames.mOverscanFrame,
@@ -996,7 +996,8 @@
             mWindowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets());
         } else {
             getDisplayContent().getBounds(mTmpRect);
-            mWindowFrames.calculateInsets(windowsAreFloating, inFullscreenContainer, mTmpRect);
+            mWindowFrames.calculateInsets(
+                    windowsAreFloating, isFullscreenAndFillsDisplay, mTmpRect);
         }
 
         mWindowFrames.setDisplayCutout(
@@ -1038,9 +1039,7 @@
     // TODO: Look into whether this override is still necessary.
     @Override
     public Rect getBounds() {
-        if (isInMultiWindowMode()) {
-            return getTask().getBounds();
-        } else if (mAppToken != null){
+        if (mAppToken != null) {
             return mAppToken.getBounds();
         } else {
             return super.getBounds();
@@ -1751,6 +1750,10 @@
                 && mWindowFrames.mFrame.bottom >= displayInfo.appHeight;
     }
 
+    private boolean matchesDisplayBounds() {
+        return getDisplayContent().getBounds().equals(getBounds());
+    }
+
     /** Returns true if last applied config was not yet requested by client. */
     boolean isConfigChanged() {
         return !getLastReportedConfiguration().equals(getConfiguration());
@@ -3114,20 +3117,16 @@
         return getDisplayContent().mCurrentFocus == this;
     }
 
-    @Override
-    public boolean isInMultiWindowMode() {
-        final Task task = getTask();
-        return task != null && !task.isFullscreen();
-    }
 
     /** Is this window in a container that takes up the entire screen space? */
-    private boolean inFullscreenContainer() {
-        return mAppToken == null || (mAppToken.matchParentBounds() && !isInMultiWindowMode());
+    private boolean inAppWindowThatMatchesParentBounds() {
+        return mAppToken == null || (mAppToken.matchParentBounds() && !inMultiWindowMode());
     }
 
-    /** @return true when the window is in fullscreen task, but has non-fullscreen bounds set. */
+    /** @return true when the window is in fullscreen mode, but has non-fullscreen bounds set, or
+     *          is transitioning into/out-of fullscreen. */
     boolean isLetterboxedAppWindow() {
-        return !isInMultiWindowMode() && mAppToken != null && !mAppToken.matchParentBounds()
+        return !inMultiWindowMode() && !matchesDisplayBounds()
                 || isLetterboxedForDisplayCutoutLw();
     }
 
@@ -3494,7 +3493,7 @@
         final int pw = containingFrame.width();
         final int ph = containingFrame.height();
         final Task task = getTask();
-        final boolean inNonFullscreenContainer = !inFullscreenContainer();
+        final boolean inNonFullscreenContainer = !inAppWindowThatMatchesParentBounds();
         final boolean noLimits = (mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
 
         // We need to fit it to the display if either
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 92bb082..780d471 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -26,7 +26,6 @@
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
@@ -792,16 +791,10 @@
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
                 + w.getDecorFrame() + " mSystemDecorRect=" + mSystemDecorRect);
 
-        final Task task = w.getTask();
-        final boolean fullscreen = w.fillsDisplay() || (task != null && task.isFullscreen());
-        final boolean isFreeformResizing =
-                w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
-
         // We use the clip rect as provided by the tranformation for non-fullscreen windows to
         // avoid premature clipping with the system decor rect.
         clipRect.set(mSystemDecorRect);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
-                + " fullscreen=" + fullscreen);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect);
 
         w.expandForSurfaceInsets(clipRect);
 
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
index a4ee907..8c65884 100644
--- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -93,8 +93,8 @@
     void writeTraceToFile(File traceFile) throws IOException {
         synchronized (mBufferLock) {
             traceFile.delete();
-            traceFile.setReadable(true, false);
             try (OutputStream os = new FileOutputStream(traceFile)) {
+                traceFile.setReadable(true /* readable */, false /* ownerOnly */);
                 ProtoOutputStream proto = new ProtoOutputStream();
                 proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
                 os.write(proto.getBytes());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index c072d4e..83c0af9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -59,7 +59,7 @@
     public void setUpOnDisplay(DisplayContent dc) {
         mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(dc, false /* skipOnParentChanged */);
+        mToken = WindowTestUtils.createTestAppWindowToken(dc);
 
         mTask.addChild(mToken, 0);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 5e12a95..81133d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 
@@ -77,4 +78,21 @@
                             TRANSIT_TASK_CLOSE));
         }
     }
+
+    @Test
+    public void testChangeIsNotOverwritten() {
+        synchronized (mWm.mGlobalLock) {
+            final AppWindowToken behind = createAppWindowToken(mDisplayContent,
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+            final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+            translucentOpening.setFillsParent(false);
+            translucentOpening.setHidden(true);
+            mDisplayContent.mOpeningApps.add(behind);
+            mDisplayContent.mOpeningApps.add(translucentOpening);
+            assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
+                    mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
+                            TRANSIT_TASK_CHANGE_WINDOWING_MODE));
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index a98a604..db04f11 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -60,7 +60,7 @@
         MockitoAnnotations.initMocks(this);
 
         mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */);
+                ACTIVITY_TYPE_STANDARD);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 68b40b9..d17e5c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -16,8 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
@@ -48,7 +46,6 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.res.Configuration;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
@@ -81,8 +78,7 @@
     public void setUp() throws Exception {
         mStack = createTaskStackOnDisplay(mDisplayContent);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent,
-                false /* skipOnParentChanged */);
+        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
 
         mTask.addChild(mToken, 0);
     }
@@ -219,9 +215,6 @@
 
     @Test
     public void testSizeCompatBounds() {
-        // The real surface transaction is unnecessary.
-        mToken.setSkipPrepareSurfaces(true);
-
         final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
@@ -479,32 +472,6 @@
         assertHasStartingWindow(tokenBottom);
     }
 
-    @Test
-    public void testTransitionAnimationPositionAndBounds() {
-        final Rect stackBounds = new Rect(
-                0/* left */, 0 /* top */, 1000 /* right */, 1000 /* bottom */);
-        final Rect taskBounds = new Rect(
-                100/* left */, 200 /* top */, 600 /* right */, 600 /* bottom */);
-        mStack.setBounds(stackBounds);
-        mTask.setBounds(taskBounds);
-
-        mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        assertTransitionAnimationPositionAndBounds(taskBounds.left, taskBounds.top, stackBounds);
-
-        mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        assertTransitionAnimationPositionAndBounds(stackBounds.left, stackBounds.top, stackBounds);
-    }
-
-    private void assertTransitionAnimationPositionAndBounds(int expectedX, int expectedY,
-            Rect expectedBounds) {
-        final Point outPosition = new Point();
-        final Rect outBounds = new Rect();
-        mToken.getAnimationBounds(outPosition, outBounds);
-        assertEquals(expectedX, outPosition.x);
-        assertEquals(expectedY, outPosition.y);
-        assertEquals(expectedBounds, outBounds);
-    }
-
     private void assertHasStartingWindow(AppWindowToken atoken) {
         assertNotNull(atoken.startingSurface);
         assertNotNull(atoken.startingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 2ccdb9e..78fca0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
@@ -27,7 +28,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
-import android.app.ActivityManager.TaskDescription;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -54,23 +54,15 @@
 @Presubmit
 public class WindowFrameTests extends WindowTestsBase {
 
-    private WindowToken mWindowToken;
     private final IWindow mIWindow = new TestIWindow();
     private final Rect mEmptyRect = new Rect();
 
-    static class WindowStateWithTask extends WindowState {
-        final Task mTask;
+    static class FrameTestWindowState extends WindowState {
         boolean mDockedResizingForTest = false;
-        WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
-                WindowManager.LayoutParams attrs, Task t) {
+        FrameTestWindowState(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
+                WindowManager.LayoutParams attrs) {
             super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
                     false /* ownerCanAddInternalSystemWindow */);
-            mTask = t;
-        }
-
-        @Override
-        Task getTask() {
-            return mTask;
         }
 
         @Override
@@ -79,52 +71,10 @@
         }
     }
 
-    private static class TaskWithBounds extends Task {
-        Rect mBounds;
-        final Rect mOverrideDisplayedBounds = new Rect();
-        boolean mFullscreenForTest = true;
-
-        TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) {
-            super(0, stack, 0, wm, 0, false, new TaskDescription(), null);
-            setBounds(bounds);
-        }
-
-        @Override
-        public int setBounds(Rect bounds) {
-            mBounds = bounds;
-            return super.setBounds(bounds);
-        }
-
-        @Override
-        public Rect getBounds() {
-            return mBounds;
-        }
-
-        @Override
-        public void getBounds(Rect out) {
-            out.set(mBounds);
-        }
-
-        @Override
-        public void getRequestedOverrideBounds(Rect outBounds) {
-            outBounds.set(mBounds);
-        }
-        @Override
-        Rect getOverrideDisplayedBounds() {
-            return mOverrideDisplayedBounds;
-        }
-        @Override
-        boolean isFullscreen() {
-            return mFullscreenForTest;
-        }
-    }
-
     TaskStack mStubStack;
 
     @Before
     public void setUp() throws Exception {
-        mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         mStubStack = mock(TaskStack.class);
     }
 
@@ -168,7 +118,8 @@
                 expectedRect.bottom);
     }
 
-    private void assertPolicyCrop(WindowStateWithTask w, int left, int top, int right, int bottom) {
+    private void assertPolicyCrop(
+            FrameTestWindowState w, int left, int top, int right, int bottom) {
         Rect policyCrop = new Rect();
         w.calculatePolicyCrop(policyCrop);
         assertRect(policyCrop, left, top, right, bottom);
@@ -177,8 +128,7 @@
     @Test
     public void testLayoutInFullscreenTaskInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final int bottomContentInset = 100;
@@ -235,8 +185,7 @@
     @Test
     public void testLayoutInFullscreenTaskNoInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         // With no insets or system decor all the frames incoming from PhoneWindowManager
@@ -323,9 +272,11 @@
         final int taskRight = logicalWidth / 4 * 3;
         final int taskBottom = logicalHeight / 4 * 3;
         final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
-        task.mFullscreenForTest = false;
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
+        // Use split-screen because it is non-fullscreen, but also not floating
+        task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        task.setBounds(taskBounds);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -359,8 +310,8 @@
         final int insetTop = logicalHeight / 5;
         final int insetRight = insetLeft + (taskRight - taskLeft);
         final int insetBottom = insetTop + (taskBottom - taskTop);
-        task.mOverrideDisplayedBounds.set(taskBounds);
-        task.mBounds.set(insetLeft, insetTop, insetRight, insetBottom);
+        task.setOverrideDisplayedBounds(taskBounds);
+        task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -373,8 +324,7 @@
 
     @Test
     public void testCalculatePolicyCrop() {
-        final WindowStateWithTask w = createWindow(
-                new TaskWithBounds(mStubStack, mWm, null), MATCH_PARENT, MATCH_PARENT);
+        final FrameTestWindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
@@ -439,9 +389,11 @@
         final int taskRight = logicalWidth / 4 * 3;
         final int taskBottom = logicalHeight / 4 * 3;
         final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
-        task.mFullscreenForTest = false;
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
+        // Use split-screen because it is non-fullscreen, but also not floating
+        task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        task.setBounds(taskBounds);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -461,7 +413,8 @@
         config.windowConfiguration.setBounds(cf);
         w.mAppToken.onRequestedOverrideConfigurationChanged(config);
         pf.set(0, 0, logicalWidth, logicalHeight);
-        task.mFullscreenForTest = true;
+        task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        task.setBounds(null);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
         assertFrame(w, cf.left, cf.top, cf.right, cf.bottom);
@@ -472,8 +425,7 @@
     @Test
     public void testDisplayCutout() {
         // Regular fullscreen task and window
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, 1000, 2000);
@@ -496,11 +448,10 @@
     @Test
     public void testDisplayCutout_tempDisplayedBounds() {
         // Regular fullscreen task and window
-        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm,
-                new Rect(0, 0, 1000, 2000));
-        task.mFullscreenForTest = false;
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
+        task.setBounds(new Rect(0, 0, 1000, 2000));
         task.setOverrideDisplayedBounds(new Rect(0, -500, 1000, 1500));
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, -500, 1000, 1500);
@@ -523,12 +474,10 @@
     @Test
     public void testFreeformContentInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
         task.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        ((TaskWithBounds) task).mFullscreenForTest = false;
-        w.setWindowingMode(WINDOWING_MODE_FREEFORM);
 
         DisplayContent dc = mWm.getDefaultDisplayContentLocked();
         dc.mInputMethodTarget = w;
@@ -551,7 +500,6 @@
         final Rect winRect = new Rect(200, 200, 300, 500);
 
         task.setBounds(winRect);
-        w.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
 
@@ -580,11 +528,16 @@
         assertEquals(winRect, w.getFrameLw());
     }
 
-    private WindowStateWithTask createWindow(Task task, int width, int height) {
+    private FrameTestWindowState createWindow(int width, int height) {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
         attrs.width = width;
         attrs.height = height;
 
-        return new WindowStateWithTask(mWm, mIWindow, mWindowToken, attrs, task);
+        AppWindowToken token = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+
+        FrameTestWindowState ws = new FrameTestWindowState(mWm, mIWindow, token, attrs);
+        token.addWindow(ws);
+        return ws;
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 0dec8ee..a7a785d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -56,24 +56,15 @@
 
     static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
         synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc, true /* skipOnParentChanged */);
-        }
-    }
-
-    static TestAppWindowToken createTestAppWindowToken(DisplayContent dc,
-            boolean skipOnParentChanged) {
-        synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc, skipOnParentChanged);
+            return new TestAppWindowToken(dc);
         }
     }
 
     /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
     static class TestAppWindowToken extends AppWindowToken {
         boolean mOnTop = false;
-        private boolean mSkipPrepareSurfaces;
-        boolean mSkipOnParentChanged = true;
 
-        private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) {
+        private TestAppWindowToken(DisplayContent dc) {
             super(dc.mWmService, new IApplicationToken.Stub() {
                 @Override
                 public String getName() {
@@ -81,7 +72,6 @@
                 }
             }, new ComponentName("", ""), false, dc, true /* fillsParent */);
             mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT;
-            mSkipOnParentChanged = skipOnParentChanged;
             mActivityRecord = mock(ActivityRecord.class);
             mActivityRecord.app = mock(WindowProcessController.class);
         }
@@ -103,44 +93,10 @@
         }
 
         @Override
-        void onParentChanged() {
-            if (!mSkipOnParentChanged) {
-                super.onParentChanged();
-            } else {
-                updateConfigurationFromParent(this);
-            }
-        }
-
-        @Override
         boolean isOnTop() {
             return mOnTop;
         }
 
-        @Override
-        void prepareSurfaces() {
-            if (!mSkipPrepareSurfaces) {
-                super.prepareSurfaces();
-            }
-        }
-
-        void setSkipPrepareSurfaces(boolean ignore) {
-            mSkipPrepareSurfaces = ignore;
-        }
-    }
-
-    /**
-     * Used when we don't want to perform surface related operation in
-     * {@link WindowContainer#onParentChanged} or the overridden method, but the configuration
-     * still needs to propagate from parent.
-     *
-     * @see ConfigurationContainer#onParentChanged
-     */
-    static void updateConfigurationFromParent(WindowContainer container) {
-        final WindowContainer parent = container.getParent();
-        if (parent != null) {
-            container.onConfigurationChanged(parent.getConfiguration());
-            container.onMergedOverrideConfigurationChanged();
-        }
     }
 
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
@@ -246,10 +202,5 @@
 
             mHasSurface = hadSurface;
         }
-
-        @Override
-        void onParentChanged() {
-            updateConfigurationFromParent(this);
-        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 032eba1..8c37ca5e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -229,10 +229,11 @@
         } catch (Exception e) {
             Log.e(TAG, "Failed to tear down test", e);
             throw e;
+        } finally {
+            mMockTracker.close();
+            mMockTracker = null;
         }
 
-        mMockTracker.close();
-        mMockTracker = null;
     }
 
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
@@ -269,16 +270,10 @@
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
-        return createTestAppWindowToken(dc, windowingMode, activityType,
-                false /*skipOnParentChanged */);
-    }
-
-    WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
-            windowingMode, int activityType, boolean skipOnParentChanged) {
         final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final WindowTestUtils.TestAppWindowToken appWindowToken =
-                WindowTestUtils.createTestAppWindowToken(dc, skipOnParentChanged);
+                WindowTestUtils.createTestAppWindowToken(dc);
         task.addChild(appWindowToken, 0);
         return appWindowToken;
     }