Merge "Pull out Settings usage into utility"
diff --git a/api/current.txt b/api/current.txt
index 55983c8..e5acc40 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -42916,6 +42916,7 @@
     field public static final int IP_MULTICAST_TTL;
     field public static final int IP_TOS;
     field public static final int IP_TTL;
+    field public static final int MAP_ANONYMOUS;
     field public static final int MAP_FIXED;
     field public static final int MAP_PRIVATE;
     field public static final int MAP_SHARED;
@@ -50390,34 +50391,34 @@
   }
 
   public class TextureView extends android.view.View {
-    ctor public TextureView(android.content.Context);
-    ctor public TextureView(android.content.Context, android.util.AttributeSet);
-    ctor public TextureView(android.content.Context, android.util.AttributeSet, int);
-    ctor public TextureView(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public TextureView(@NonNull android.content.Context);
+    ctor public TextureView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public TextureView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int);
+    ctor public TextureView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int, int);
     method public final void draw(android.graphics.Canvas);
-    method public android.graphics.Bitmap getBitmap();
-    method public android.graphics.Bitmap getBitmap(int, int);
-    method public android.graphics.Bitmap getBitmap(android.graphics.Bitmap);
-    method public android.graphics.SurfaceTexture getSurfaceTexture();
-    method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener();
-    method public android.graphics.Matrix getTransform(android.graphics.Matrix);
+    method @Nullable public android.graphics.Bitmap getBitmap();
+    method @Nullable public android.graphics.Bitmap getBitmap(int, int);
+    method @NonNull public android.graphics.Bitmap getBitmap(@NonNull android.graphics.Bitmap);
+    method @Nullable public android.graphics.SurfaceTexture getSurfaceTexture();
+    method @Nullable public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener();
+    method @NonNull public android.graphics.Matrix getTransform(@Nullable android.graphics.Matrix);
     method public boolean isAvailable();
-    method public android.graphics.Canvas lockCanvas();
-    method public android.graphics.Canvas lockCanvas(android.graphics.Rect);
+    method @Nullable public android.graphics.Canvas lockCanvas();
+    method @Nullable public android.graphics.Canvas lockCanvas(@Nullable android.graphics.Rect);
     method protected final void onDraw(android.graphics.Canvas);
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setOpaque(boolean);
-    method public void setSurfaceTexture(android.graphics.SurfaceTexture);
-    method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
-    method public void setTransform(android.graphics.Matrix);
-    method public void unlockCanvasAndPost(android.graphics.Canvas);
+    method public void setSurfaceTexture(@NonNull android.graphics.SurfaceTexture);
+    method public void setSurfaceTextureListener(@Nullable android.view.TextureView.SurfaceTextureListener);
+    method public void setTransform(@Nullable android.graphics.Matrix);
+    method public void unlockCanvasAndPost(@NonNull android.graphics.Canvas);
   }
 
   public static interface TextureView.SurfaceTextureListener {
-    method public void onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int);
-    method public boolean onSurfaceTextureDestroyed(android.graphics.SurfaceTexture);
-    method public void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int);
-    method public void onSurfaceTextureUpdated(android.graphics.SurfaceTexture);
+    method public void onSurfaceTextureAvailable(@NonNull android.graphics.SurfaceTexture, int, int);
+    method public boolean onSurfaceTextureDestroyed(@NonNull android.graphics.SurfaceTexture);
+    method public void onSurfaceTextureSizeChanged(@NonNull android.graphics.SurfaceTexture, int, int);
+    method public void onSurfaceTextureUpdated(@NonNull android.graphics.SurfaceTexture);
   }
 
   public class TouchDelegate {
@@ -50677,7 +50678,7 @@
     method public final int getScrollY();
     method @android.view.ViewDebug.ExportedProperty(category="drawing") @ColorInt public int getSolidColor();
     method @LayoutRes public int getSourceLayoutResId();
-    method @android.view.ViewDebug.ExportedProperty(category="accessibility") @Nullable public final CharSequence getStateDescription();
+    method @android.view.ViewDebug.ExportedProperty(category="accessibility") @Nullable public CharSequence getStateDescription();
     method public android.animation.StateListAnimator getStateListAnimator();
     method protected int getSuggestedMinimumHeight();
     method protected int getSuggestedMinimumWidth();
diff --git a/api/system-current.txt b/api/system-current.txt
index 9a241e8..213ea31 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5241,6 +5241,7 @@
   }
 
   public class BatteryStatsManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.CellularBatteryStats getCellularBatteryStats();
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
@@ -5748,6 +5749,26 @@
 
 package android.os.connectivity {
 
+  public final class CellularBatteryStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getEnergyConsumedMaMillis();
+    method public long getIdleTimeMillis();
+    method public long getKernelActiveTimeMillis();
+    method public long getLoggingDurationMillis();
+    method public long getMonitoredRailChargeConsumedMaMillis();
+    method public long getNumBytesRx();
+    method public long getNumBytesTx();
+    method public long getNumPacketsRx();
+    method public long getNumPacketsTx();
+    method public long getRxTimeMillis();
+    method public long getSleepTimeMillis();
+    method @NonNull public long[] getTimeInRatMicros();
+    method @NonNull public long[] getTimeInRxSignalStrengthLevelMicros();
+    method @NonNull public long[] getTxTimeMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.CellularBatteryStats> CREATOR;
+  }
+
   public final class WifiBatteryStats implements android.os.Parcelable {
     method public int describeContents();
     method public long getEnergyConsumedMaMillis();
@@ -8408,7 +8429,6 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
-    method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
@@ -8467,6 +8487,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
+    method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
@@ -9084,20 +9105,20 @@
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.function.Consumer<java.lang.Boolean>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTtyOverVolteEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled();
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
@@ -9557,9 +9578,9 @@
   }
 
   public interface RegistrationManager {
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
     field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0
     field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index efb9f6bb..47118a8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,7 +17,6 @@
 package android.app;
 
 import static android.annotation.Dimension.DP;
-import static android.graphics.drawable.Icon.TYPE_BITMAP;
 
 import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
 
@@ -8741,26 +8740,20 @@
              * If your app produces multiple bubbles, the image should be unique for each of them.
              * </p>
              *
-             * <p>The shape of a bubble icon is adaptive and can match the device theme.
+             * <p>The shape of a bubble icon is adaptive and will match the device theme.
              *
-             * If your icon is bitmap-based, you should create it using
-             * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise this method will throw.
-             *
-             * If your icon is not bitmap-based, you should expect that the icon will be tinted.
+             * Ideally your icon should be constructed via
+             * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise, the icon will be shrunk
+             * and placed on an adaptive shape.
              * </p>
              *
-             * @throws IllegalArgumentException if icon is null or a non-adaptive bitmap
+             * @throws IllegalArgumentException if icon is null.
              */
             @NonNull
             public BubbleMetadata.Builder setIcon(@NonNull Icon icon) {
                 if (icon == null) {
                     throw new IllegalArgumentException("Bubbles require non-null icon");
                 }
-                if (icon.getType() == TYPE_BITMAP) {
-                    throw new IllegalArgumentException("When using bitmap based icons, Bubbles "
-                            + "require TYPE_ADAPTIVE_BITMAP, please use"
-                            + " Icon#createWithAdaptiveBitmap instead");
-                }
                 mIcon = icon;
                 return this;
             }
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 367a868..e5650ae 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -23,6 +23,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.os.connectivity.CellularBatteryStats;
 import android.os.connectivity.WifiBatteryStats;
 
 import com.android.internal.app.IBatteryStats;
@@ -158,6 +159,21 @@
     }
 
     /**
+     * Retrieves all the cellular related battery stats.
+     *
+     * @return Instance of {@link CellularBatteryStats}.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public @NonNull CellularBatteryStats getCellularBatteryStats() {
+        try {
+            return mBatteryStats.getCellularBatteryStats();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return null;
+        }
+    }
+
+    /**
      * Retrieves all the wifi related battery stats.
      *
      * @return Instance of {@link WifiBatteryStats}.
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index 2e09040..caa4068 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -15,241 +15,367 @@
  */
 package android.os.connectivity;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.BatteryStats;
 import android.os.Parcel;
 import android.os.Parcelable;
-
+import android.telephony.Annotation.NetworkType;
 import android.telephony.ModemActivityInfo;
 import android.telephony.SignalStrength;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * API for Cellular power stats
  *
  * @hide
  */
+@SystemApi
 public final class CellularBatteryStats implements Parcelable {
 
-  private long mLoggingDurationMs;
-  private long mKernelActiveTimeMs;
-  private long mNumPacketsTx;
-  private long mNumBytesTx;
-  private long mNumPacketsRx;
-  private long mNumBytesRx;
-  private long mSleepTimeMs;
-  private long mIdleTimeMs;
-  private long mRxTimeMs;
-  private long mEnergyConsumedMaMs;
-  private long[] mTimeInRatMs;
-  private long[] mTimeInRxSignalStrengthLevelMs;
-  private long[] mTxTimeMs;
-  private long mMonitoredRailChargeConsumedMaMs;
+    private long mLoggingDurationMs = 0;
+    private long mKernelActiveTimeMs = 0;
+    private long mNumPacketsTx = 0;
+    private long mNumBytesTx = 0;
+    private long mNumPacketsRx = 0;
+    private long mNumBytesRx = 0;
+    private long mSleepTimeMs = 0;
+    private long mIdleTimeMs = 0;
+    private long mRxTimeMs = 0;
+    private long mEnergyConsumedMaMs = 0;
+    private long[] mTimeInRatMs = new long[BatteryStats.NUM_DATA_CONNECTION_TYPES];
+    private long[] mTimeInRxSignalStrengthLevelMs =
+            new long[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
+    private long[] mTxTimeMs = new long[ModemActivityInfo.TX_POWER_LEVELS];
+    private long mMonitoredRailChargeConsumedMaMs = 0;
 
-  public static final @android.annotation.NonNull Parcelable.Creator<CellularBatteryStats> CREATOR = new
-      Parcelable.Creator<CellularBatteryStats>() {
-        public CellularBatteryStats createFromParcel(Parcel in) {
-          return new CellularBatteryStats(in);
-        }
+    public static final @NonNull Parcelable.Creator<CellularBatteryStats> CREATOR =
+            new Parcelable.Creator<CellularBatteryStats>() {
+                public CellularBatteryStats createFromParcel(Parcel in) {
+                    return new CellularBatteryStats(in);
+                }
 
-        public CellularBatteryStats[] newArray(int size) {
-          return new CellularBatteryStats[size];
-        }
-      };
+                public CellularBatteryStats[] newArray(int size) {
+                    return new CellularBatteryStats[size];
+                }
+            };
 
-  public CellularBatteryStats() {
-    initialize();
-  }
+    /** @hide **/
+    public CellularBatteryStats() {}
 
-  public void writeToParcel(Parcel out, int flags) {
-    out.writeLong(mLoggingDurationMs);
-    out.writeLong(mKernelActiveTimeMs);
-    out.writeLong(mNumPacketsTx);
-    out.writeLong(mNumBytesTx);
-    out.writeLong(mNumPacketsRx);
-    out.writeLong(mNumBytesRx);
-    out.writeLong(mSleepTimeMs);
-    out.writeLong(mIdleTimeMs);
-    out.writeLong(mRxTimeMs);
-    out.writeLong(mEnergyConsumedMaMs);
-    out.writeLongArray(mTimeInRatMs);
-    out.writeLongArray(mTimeInRxSignalStrengthLevelMs);
-    out.writeLongArray(mTxTimeMs);
-    out.writeLong(mMonitoredRailChargeConsumedMaMs);
-  }
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeLong(mLoggingDurationMs);
+        out.writeLong(mKernelActiveTimeMs);
+        out.writeLong(mNumPacketsTx);
+        out.writeLong(mNumBytesTx);
+        out.writeLong(mNumPacketsRx);
+        out.writeLong(mNumBytesRx);
+        out.writeLong(mSleepTimeMs);
+        out.writeLong(mIdleTimeMs);
+        out.writeLong(mRxTimeMs);
+        out.writeLong(mEnergyConsumedMaMs);
+        out.writeLongArray(mTimeInRatMs);
+        out.writeLongArray(mTimeInRxSignalStrengthLevelMs);
+        out.writeLongArray(mTxTimeMs);
+        out.writeLong(mMonitoredRailChargeConsumedMaMs);
+    }
 
-  public void readFromParcel(Parcel in) {
-    mLoggingDurationMs = in.readLong();
-    mKernelActiveTimeMs = in.readLong();
-    mNumPacketsTx = in.readLong();
-    mNumBytesTx = in.readLong();
-    mNumPacketsRx = in.readLong();
-    mNumBytesRx = in.readLong();
-    mSleepTimeMs = in.readLong();
-    mIdleTimeMs = in.readLong();
-    mRxTimeMs = in.readLong();
-    mEnergyConsumedMaMs = in.readLong();
-    in.readLongArray(mTimeInRatMs);
-    in.readLongArray(mTimeInRxSignalStrengthLevelMs);
-    in.readLongArray(mTxTimeMs);
-    mMonitoredRailChargeConsumedMaMs = in.readLong();
-  }
+    private void readFromParcel(Parcel in) {
+        mLoggingDurationMs = in.readLong();
+        mKernelActiveTimeMs = in.readLong();
+        mNumPacketsTx = in.readLong();
+        mNumBytesTx = in.readLong();
+        mNumPacketsRx = in.readLong();
+        mNumBytesRx = in.readLong();
+        mSleepTimeMs = in.readLong();
+        mIdleTimeMs = in.readLong();
+        mRxTimeMs = in.readLong();
+        mEnergyConsumedMaMs = in.readLong();
+        in.readLongArray(mTimeInRatMs);
+        in.readLongArray(mTimeInRxSignalStrengthLevelMs);
+        in.readLongArray(mTxTimeMs);
+        mMonitoredRailChargeConsumedMaMs = in.readLong();
+    }
 
-  public long getLoggingDurationMs() {
-    return mLoggingDurationMs;
-  }
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (!(other instanceof CellularBatteryStats)) return false;
+        if (other == this) return true;
+        CellularBatteryStats otherStats = (CellularBatteryStats) other;
+        return this.mLoggingDurationMs == otherStats.mLoggingDurationMs
+                && this.mKernelActiveTimeMs == otherStats.mKernelActiveTimeMs
+                && this.mNumPacketsTx == otherStats.mNumPacketsTx
+                && this.mNumBytesTx == otherStats.mNumBytesTx
+                && this.mNumPacketsRx == otherStats.mNumPacketsRx
+                && this.mNumBytesRx == otherStats.mNumBytesRx
+                && this.mSleepTimeMs == otherStats.mSleepTimeMs
+                && this.mIdleTimeMs == otherStats.mIdleTimeMs
+                && this.mRxTimeMs == otherStats.mRxTimeMs
+                && this.mEnergyConsumedMaMs == otherStats.mEnergyConsumedMaMs
+                && Arrays.equals(this.mTimeInRatMs, otherStats.mTimeInRatMs)
+                && Arrays.equals(this.mTimeInRxSignalStrengthLevelMs,
+                    otherStats.mTimeInRxSignalStrengthLevelMs)
+                && Arrays.equals(this.mTxTimeMs, otherStats.mTxTimeMs)
+                && this.mMonitoredRailChargeConsumedMaMs
+                    == otherStats.mMonitoredRailChargeConsumedMaMs;
+    }
 
-  public long getKernelActiveTimeMs() {
-    return mKernelActiveTimeMs;
-  }
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLoggingDurationMs, mKernelActiveTimeMs, mNumPacketsTx,
+                mNumBytesTx, mNumPacketsRx, mNumBytesRx, mSleepTimeMs, mIdleTimeMs,
+                mRxTimeMs, mEnergyConsumedMaMs, Arrays.hashCode(mTimeInRatMs),
+                Arrays.hashCode(mTimeInRxSignalStrengthLevelMs), Arrays.hashCode(mTxTimeMs),
+                mMonitoredRailChargeConsumedMaMs);
+    }
 
-  public long getNumPacketsTx() {
-    return mNumPacketsTx;
-  }
+    /**
+     * Returns the duration for which these cellular stats were collected.
+     *
+     * @return Duration of stats collection in milliseconds.
+     */
+    public long getLoggingDurationMillis() {
+        return mLoggingDurationMs;
+    }
 
-  public long getNumBytesTx() {
-    return mNumBytesTx;
-  }
+    /**
+     * Returns the duration for which the kernel was active within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of kernel active time in milliseconds.
+     */
+    public long getKernelActiveTimeMillis() {
+        return mKernelActiveTimeMs;
+    }
 
-  public long getNumPacketsRx() {
-    return mNumPacketsRx;
-  }
+    /**
+     * Returns the number of packets transmitted over cellular within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of packets transmitted.
+     */
+    public long getNumPacketsTx() {
+        return mNumPacketsTx;
+    }
 
-  public long getNumBytesRx() {
-    return mNumBytesRx;
-  }
+    /**
+     * Returns the number of packets received over cellular within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of packets received.
+     */
+    public long getNumBytesTx() {
+        return mNumBytesTx;
+    }
 
-  public long getSleepTimeMs() {
-    return mSleepTimeMs;
-  }
+    /**
+     * Returns the number of bytes transmitted over cellular within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of bytes transmitted.
+     */
+    public long getNumPacketsRx() {
+        return mNumPacketsRx;
+    }
 
-  public long getIdleTimeMs() {
-    return mIdleTimeMs;
-  }
+    /**
+     * Returns the number of bytes received over cellular within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of bytes received.
+     */
+    public long getNumBytesRx() {
+        return mNumBytesRx;
+    }
 
-  public long getRxTimeMs() {
-    return mRxTimeMs;
-  }
+    /**
+     * Returns the duration for which the device was sleeping within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of sleep time in milliseconds.
+     */
+    public long getSleepTimeMillis() {
+        return mSleepTimeMs;
+    }
 
-  public long getEnergyConsumedMaMs() {
-    return mEnergyConsumedMaMs;
-  }
+    /**
+     * Returns the duration for which the device was idle within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of idle time in milliseconds.
+     */
+    public long getIdleTimeMillis() {
+        return mIdleTimeMs;
+    }
 
-  public long[] getTimeInRatMs() {
-    return mTimeInRatMs;
-  }
+    /**
+     * Returns the duration for which the device was receiving over cellular within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of cellular reception time in milliseconds.
+     */
+    public long getRxTimeMillis() {
+        return mRxTimeMs;
+    }
 
-  public long[] getTimeInRxSignalStrengthLevelMs() {
-    return mTimeInRxSignalStrengthLevelMs;
-  }
+    /**
+     * Returns an estimation of energy consumed by cellular chip within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Energy consumed in milli-ampere milliseconds (mAmS).
+     */
+    public long getEnergyConsumedMaMillis() {
+        return mEnergyConsumedMaMs;
+    }
 
-  public long[] getTxTimeMs() {
-    return mTxTimeMs;
-  }
+    /**
+     * Returns the time in microseconds that the phone has been running with
+     * the given data connection.
+     *
+     * @return Amount of time phone spends in various Radio Access Technologies in microseconds.
+     * The index is {@link NetworkType}.
+     */
+    @NonNull
+    public long[] getTimeInRatMicros() {
+        return mTimeInRatMs;
+    }
 
-  public long getMonitoredRailChargeConsumedMaMs() {
-    return mMonitoredRailChargeConsumedMaMs;
-  }
+    /**
+     * Returns the time in microseconds that the phone has been running with
+     * the given signal strength.
+     *
+     * @return Amount of time phone spends in various cellular rx signal strength levels
+     * in microseconds. The index is signal strength bin.
+     */
+    @NonNull
+    public long[] getTimeInRxSignalStrengthLevelMicros() {
+        return mTimeInRxSignalStrengthLevelMs;
+    }
 
-  public void setLoggingDurationMs(long t) {
-    mLoggingDurationMs = t;
-    return;
-  }
+    /**
+     * Returns the duration for which the device was transmitting over cellular within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of cellular transmission time in milliseconds.
+     * Tx(transmit) power index below
+     * <ul>
+     *   <li> index 0 = tx_power < 0dBm. </li>
+     *   <li> index 1 = 0dBm < tx_power < 5dBm. </li>
+     *   <li> index 2 = 5dBm < tx_power < 15dBm. </li>
+     *   <li> index 3 = 15dBm < tx_power < 20dBm. </li>
+     *   <li> index 4 = tx_power > 20dBm. </li>
+     * </ul>
+     */
+    @NonNull
+    public long[] getTxTimeMillis() {
+        return mTxTimeMs;
+    }
 
-  public void setKernelActiveTimeMs(long t) {
-    mKernelActiveTimeMs = t;
-    return;
-  }
+    /**
+     * Returns the energy consumed by cellular chip within {@link #getLoggingDurationMillis()}.
+     *
+     * @return Energy consumed in milli-ampere milli-seconds (mAmS).
+     */
+    public long getMonitoredRailChargeConsumedMaMillis() {
+        return mMonitoredRailChargeConsumedMaMs;
+    }
 
-  public void setNumPacketsTx(long n) {
-    mNumPacketsTx = n;
-    return;
-  }
+    /** @hide **/
+    public void setLoggingDurationMillis(long t) {
+        mLoggingDurationMs = t;
+        return;
+    }
 
-  public void setNumBytesTx(long b) {
-    mNumBytesTx = b;
-    return;
-  }
+    /** @hide **/
+    public void setKernelActiveTimeMillis(long t) {
+        mKernelActiveTimeMs = t;
+        return;
+    }
 
-  public void setNumPacketsRx(long n) {
-    mNumPacketsRx = n;
-    return;
-  }
+    /** @hide **/
+    public void setNumPacketsTx(long n) {
+        mNumPacketsTx = n;
+        return;
+    }
 
-  public void setNumBytesRx(long b) {
-    mNumBytesRx = b;
-    return;
-  }
+    /** @hide **/
+    public void setNumBytesTx(long b) {
+        mNumBytesTx = b;
+        return;
+    }
 
-  public void setSleepTimeMs(long t) {
-    mSleepTimeMs = t;
-    return;
-  }
+    /** @hide **/
+    public void setNumPacketsRx(long n) {
+        mNumPacketsRx = n;
+        return;
+    }
 
-  public void setIdleTimeMs(long t) {
-    mIdleTimeMs = t;
-    return;
-  }
+    /** @hide **/
+    public void setNumBytesRx(long b) {
+        mNumBytesRx = b;
+        return;
+    }
 
-  public void setRxTimeMs(long t) {
-    mRxTimeMs = t;
-    return;
-  }
+    /** @hide **/
+    public void setSleepTimeMillis(long t) {
+        mSleepTimeMs = t;
+        return;
+    }
 
-  public void setEnergyConsumedMaMs(long e) {
-    mEnergyConsumedMaMs = e;
-    return;
-  }
+    /** @hide **/
+    public void setIdleTimeMillis(long t) {
+        mIdleTimeMs = t;
+        return;
+    }
 
-  public void setTimeInRatMs(long[] t) {
-    mTimeInRatMs = Arrays.copyOfRange(t, 0,
-        Math.min(t.length, BatteryStats.NUM_DATA_CONNECTION_TYPES));
-    return;
-  }
+    /** @hide **/
+    public void setRxTimeMillis(long t) {
+        mRxTimeMs = t;
+        return;
+    }
 
-  public void setTimeInRxSignalStrengthLevelMs(long[] t) {
-    mTimeInRxSignalStrengthLevelMs = Arrays.copyOfRange(t, 0,
-        Math.min(t.length, SignalStrength.NUM_SIGNAL_STRENGTH_BINS));
-    return;
-  }
+    /** @hide **/
+    public void setEnergyConsumedMaMillis(long e) {
+        mEnergyConsumedMaMs = e;
+        return;
+    }
 
-  public void setTxTimeMs(long[] t) {
-    mTxTimeMs = Arrays.copyOfRange(t, 0, Math.min(t.length, ModemActivityInfo.TX_POWER_LEVELS));
-    return;
-  }
+    /** @hide **/
+    public void setTimeInRatMicros(@NonNull long[] t) {
+        mTimeInRatMs = Arrays.copyOfRange(t, 0,
+                Math.min(t.length, BatteryStats.NUM_DATA_CONNECTION_TYPES));
+        return;
+    }
 
-  public void setMonitoredRailChargeConsumedMaMs(long monitoredRailEnergyConsumedMaMs) {
-    mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs;
-    return;
-  }
+    /** @hide **/
+    public void setTimeInRxSignalStrengthLevelMicros(@NonNull long[] t) {
+        mTimeInRxSignalStrengthLevelMs = Arrays.copyOfRange(t, 0,
+            Math.min(t.length, SignalStrength.NUM_SIGNAL_STRENGTH_BINS));
+        return;
+    }
 
-  public int describeContents() {
-    return 0;
-  }
+    /** @hide **/
+    public void setTxTimeMillis(@NonNull long[] t) {
+        mTxTimeMs = Arrays.copyOfRange(t, 0, Math.min(t.length, ModemActivityInfo.TX_POWER_LEVELS));
+        return;
+    }
 
-  private CellularBatteryStats(Parcel in) {
-    initialize();
-    readFromParcel(in);
-  }
+    /** @hide **/
+    public void setMonitoredRailChargeConsumedMaMillis(long monitoredRailEnergyConsumedMaMs) {
+        mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs;
+        return;
+    }
 
-  private void initialize() {
-    mLoggingDurationMs = 0;
-    mKernelActiveTimeMs = 0;
-    mNumPacketsTx = 0;
-    mNumBytesTx = 0;
-    mNumPacketsRx = 0;
-    mNumBytesRx = 0;
-    mSleepTimeMs = 0;
-    mIdleTimeMs = 0;
-    mRxTimeMs = 0;
-    mEnergyConsumedMaMs = 0;
-    mTimeInRatMs = new long[BatteryStats.NUM_DATA_CONNECTION_TYPES];
-    Arrays.fill(mTimeInRatMs, 0);
-    mTimeInRxSignalStrengthLevelMs = new long[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
-    Arrays.fill(mTimeInRxSignalStrengthLevelMs, 0);
-    mTxTimeMs = new long[ModemActivityInfo.TX_POWER_LEVELS];
-    Arrays.fill(mTxTimeMs, 0);
-    mMonitoredRailChargeConsumedMaMs = 0;
-    return;
-  }
-}
\ No newline at end of file
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    private CellularBatteryStats(Parcel in) {
+        readFromParcel(in);
+    }
+}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 0175ba2..5876b03 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -139,7 +140,7 @@
      *
      * @param context The context to associate this view with.
      */
-    public TextureView(Context context) {
+    public TextureView(@NonNull Context context) {
         super(context);
     }
 
@@ -149,7 +150,7 @@
      * @param context The context to associate this view with.
      * @param attrs The attributes of the XML tag that is inflating the view.
      */
-    public TextureView(Context context, AttributeSet attrs) {
+    public TextureView(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
     }
 
@@ -162,7 +163,7 @@
      *        reference to a style resource that supplies default values for
      *        the view. Can be 0 to not look for defaults.
      */
-    public TextureView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TextureView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }
 
@@ -179,7 +180,8 @@
      *        defStyleAttr is 0 or can not be found in the theme. Can be 0
      *        to not look for defaults.
      */
-    public TextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public TextureView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
@@ -484,13 +486,13 @@
      * situations, make sure this texture view is not marked opaque.</p>
      *
      * @param transform The transform to apply to the content of
-     *        this view.
+     *        this view. If null the transform will be set to identity.
      *
      * @see #getTransform(android.graphics.Matrix)
      * @see #isOpaque()
      * @see #setOpaque(boolean)
      */
-    public void setTransform(Matrix transform) {
+    public void setTransform(@Nullable Matrix transform) {
         mMatrix.set(transform);
         mMatrixChanged = true;
         invalidateParentIfNeeded();
@@ -507,7 +509,7 @@
      *
      * @see #setTransform(android.graphics.Matrix)
      */
-    public Matrix getTransform(Matrix transform) {
+    public @NonNull Matrix getTransform(@Nullable Matrix transform) {
         if (transform == null) {
             transform = new Matrix();
         }
@@ -544,7 +546,7 @@
      * @see #getBitmap(android.graphics.Bitmap)
      * @see #getBitmap(int, int)
      */
-    public Bitmap getBitmap() {
+    public @Nullable Bitmap getBitmap() {
         return getBitmap(getWidth(), getHeight());
     }
 
@@ -571,7 +573,7 @@
      * @see #getBitmap(android.graphics.Bitmap)
      * @see #getBitmap()
      */
-    public Bitmap getBitmap(int width, int height) {
+    public @Nullable Bitmap getBitmap(int width, int height) {
         if (isAvailable() && width > 0 && height > 0) {
             return getBitmap(Bitmap.createBitmap(getResources().getDisplayMetrics(),
                     width, height, Bitmap.Config.ARGB_8888));
@@ -602,7 +604,7 @@
      * @throws IllegalStateException if the hardware rendering context cannot be
      *         acquired to capture the bitmap
      */
-    public Bitmap getBitmap(Bitmap bitmap) {
+    public @NonNull Bitmap getBitmap(@NonNull Bitmap bitmap) {
         if (bitmap != null && isAvailable()) {
             applyUpdate();
             applyTransformMatrix();
@@ -649,12 +651,13 @@
      * owned by another producer. For instance, if the TextureView is being used
      * to render the camera's preview you cannot invoke this method.</p>
      *
-     * @return A Canvas used to draw into the surface.
+     * @return A Canvas used to draw into the surface, or null if the surface cannot be locked for
+     * drawing (see {@link #isAvailable()}).
      *
      * @see #lockCanvas(android.graphics.Rect)
      * @see #unlockCanvasAndPost(android.graphics.Canvas)
      */
-    public Canvas lockCanvas() {
+    public @Nullable Canvas lockCanvas() {
         return lockCanvas(null);
     }
 
@@ -669,15 +672,17 @@
      * already connected to an image producer (for instance: the camera,
      * OpenGL, a media player, etc.)
      *
-     * @param dirty Area of the surface that will be modified.
+     * @param dirty Area of the surface that will be modified. If null the area of the entire
+     *              surface is used.
 
-     * @return A Canvas used to draw into the surface.
+     * @return A Canvas used to draw into the surface, or null if the surface cannot be locked for
+     * drawing (see {@link #isAvailable()}).
      *
      * @see #lockCanvas()
      * @see #unlockCanvasAndPost(android.graphics.Canvas)
      * @see #isAvailable()
      */
-    public Canvas lockCanvas(Rect dirty) {
+    public @Nullable Canvas lockCanvas(@Nullable Rect dirty) {
         if (!isAvailable()) return null;
 
         if (mCanvas == null) {
@@ -705,7 +710,7 @@
      * @see #lockCanvas()
      * @see #lockCanvas(android.graphics.Rect)
      */
-    public void unlockCanvasAndPost(Canvas canvas) {
+    public void unlockCanvasAndPost(@NonNull Canvas canvas) {
         if (mCanvas != null && canvas == mCanvas) {
             canvas.restoreToCount(mSaveCount);
             mSaveCount = 0;
@@ -723,7 +728,7 @@
      *
      * @see #isAvailable()
      */
-    public SurfaceTexture getSurfaceTexture() {
+    public @Nullable SurfaceTexture getSurfaceTexture() {
         return mSurface;
     }
 
@@ -742,7 +747,7 @@
      * @param surfaceTexture The {@link SurfaceTexture} that the view should use.
      * @see SurfaceTexture#detachFromGLContext()
      */
-    public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
+    public void setSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) {
         if (surfaceTexture == null) {
             throw new NullPointerException("surfaceTexture must not be null");
         }
@@ -781,7 +786,7 @@
      * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
      * @see SurfaceTextureListener
      */
-    public SurfaceTextureListener getSurfaceTextureListener() {
+    public @Nullable SurfaceTextureListener getSurfaceTextureListener() {
         return mListener;
     }
 
@@ -792,25 +797,22 @@
      * @see #getSurfaceTextureListener()
      * @see SurfaceTextureListener
      */
-    public void setSurfaceTextureListener(SurfaceTextureListener listener) {
+    public void setSurfaceTextureListener(@Nullable SurfaceTextureListener listener) {
         mListener = listener;
     }
 
     @UnsupportedAppUsage
     private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
-            new SurfaceTexture.OnFrameAvailableListener() {
-        @Override
-        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
-            updateLayer();
-            invalidate();
-        }
-    };
+            surfaceTexture -> {
+                updateLayer();
+                invalidate();
+            };
 
     /**
      * This listener can be used to be notified when the surface texture
      * associated with this texture view is available.
      */
-    public static interface SurfaceTextureListener {
+    public interface SurfaceTextureListener {
         /**
          * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
          *
@@ -819,7 +821,7 @@
          * @param width The width of the surface
          * @param height The height of the surface
          */
-        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height);
+        void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height);
 
         /**
          * Invoked when the {@link SurfaceTexture}'s buffers size changed.
@@ -829,7 +831,7 @@
          * @param width The new width of the surface
          * @param height The new height of the surface
          */
-        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
+        void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height);
 
         /**
          * Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
@@ -839,7 +841,7 @@
          *
          * @param surface The surface about to be destroyed
          */
-        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface);
+        boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface);
 
         /**
          * Invoked when the specified {@link SurfaceTexture} is updated through
@@ -847,7 +849,7 @@
          *
          * @param surface The surface just updated
          */
-        public void onSurfaceTextureUpdated(SurfaceTexture surface);
+        void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface);
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1599afb..b90ce87 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8727,7 +8727,7 @@
             structure.setContextClickable(true);
         }
         structure.setClassName(getAccessibilityClassName().toString());
-        structure.setContentDescription(getContentDescription());
+        structure.setContentDescription(mContentDescription);
     }
 
     /**
@@ -9934,8 +9934,8 @@
         info.setImportantForAccessibility(isImportantForAccessibility());
         info.setPackageName(mContext.getPackageName());
         info.setClassName(getAccessibilityClassName());
-        info.setStateDescription(getStateDescription());
-        info.setContentDescription(getContentDescription());
+        info.setStateDescription(mStateDescription);
+        info.setContentDescription(mContentDescription);
 
         info.setEnabled(isEnabled());
         info.setClickable(isClickable());
@@ -10318,7 +10318,7 @@
      * @see #setStateDescription(CharSequence)
      */
     @ViewDebug.ExportedProperty(category = "accessibility")
-    public final @Nullable CharSequence getStateDescription() {
+    public @Nullable CharSequence getStateDescription() {
         return mStateDescription;
     }
 
@@ -13724,7 +13724,7 @@
      */
     @UnsupportedAppUsage
     public CharSequence getIterableTextForAccessibility() {
-        return getContentDescription();
+        return mContentDescription;
     }
 
     /**
@@ -29514,9 +29514,10 @@
         stream.addProperty("text:textAlignment", getTextAlignment());
 
         // accessibility
-        CharSequence contentDescription = getContentDescription();
         stream.addProperty("accessibility:contentDescription",
-                contentDescription == null ? "" : contentDescription.toString());
+                mContentDescription == null ? "" : mContentDescription.toString());
+        stream.addProperty("accessibility:stateDescription",
+                mStateDescription == null ? "" : mStateDescription.toString());
         stream.addProperty("accessibility:labelFor", getLabelFor());
         stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility());
     }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index f4f7d0b..6c6046f 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -93,8 +93,9 @@
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState) {
         final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
-            .setParent(mRootSurface)
-            .setName(attrs.getTitle().toString());
+                .setParent(mRootSurface)
+                .setFormat(attrs.format)
+                .setName(attrs.getTitle().toString());
         final SurfaceControl sc = b.build();
         synchronized (this) {
             mStateForWindow.put(window.asBinder(), new State(sc, attrs));
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7282008..2895621 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -328,6 +328,9 @@
      * <p>
      * The built-in mechanisms are the only currently supported zoom
      * mechanisms, so it is recommended that this setting is always enabled.
+     * However, on-screen zoom controls are deprecated in Android (see
+     * {@link android.widget.ZoomButtonsController}) so it's recommended to
+     * disable {@link #setDisplayZoomControls}.
      *
      * @param enabled whether the WebView should use its built-in zoom mechanisms
      */
@@ -347,7 +350,9 @@
     /**
      * Sets whether the WebView should display on-screen zoom controls when
      * using the built-in zoom mechanisms. See {@link #setBuiltInZoomControls}.
-     * The default is {@code true}.
+     * The default is {@code true}. However, on-screen zoom controls are deprecated
+     * in Android (see {@link android.widget.ZoomButtonsController}) so it's
+     * recommended to set this to {@code false}.
      *
      * @param enabled whether the WebView should display on-screen zoom controls
      */
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d6b32b5..f5bfe5c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12618,20 +12618,20 @@
             txTimeMs[i] = counter.getTxTimeCounters()[i].getCountLocked(which);
             totalTxTimeMs += txTimeMs[i];
         }
-        s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000);
-        s.setKernelActiveTimeMs(getMobileRadioActiveTime(rawRealTime, which) / 1000);
+        s.setLoggingDurationMillis(computeBatteryRealtime(rawRealTime, which) / 1000);
+        s.setKernelActiveTimeMillis(getMobileRadioActiveTime(rawRealTime, which) / 1000);
         s.setNumPacketsTx(getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which));
         s.setNumBytesTx(getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which));
         s.setNumPacketsRx(getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which));
         s.setNumBytesRx(getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which));
-        s.setSleepTimeMs(sleepTimeMs);
-        s.setIdleTimeMs(idleTimeMs);
-        s.setRxTimeMs(rxTimeMs);
-        s.setEnergyConsumedMaMs(energyConsumedMaMs);
-        s.setTimeInRatMs(timeInRatMs);
-        s.setTimeInRxSignalStrengthLevelMs(timeInRxSignalStrengthLevelMs);
-        s.setTxTimeMs(txTimeMs);
-        s.setMonitoredRailChargeConsumedMaMs(monitoredRailChargeConsumedMaMs);
+        s.setSleepTimeMillis(sleepTimeMs);
+        s.setIdleTimeMillis(idleTimeMs);
+        s.setRxTimeMillis(rxTimeMs);
+        s.setEnergyConsumedMaMillis(energyConsumedMaMs);
+        s.setTimeInRatMicros(timeInRatMs);
+        s.setTimeInRxSignalStrengthLevelMicros(timeInRxSignalStrengthLevelMs);
+        s.setTxTimeMillis(txTimeMs);
+        s.setMonitoredRailChargeConsumedMaMillis(monitoredRailChargeConsumedMaMs);
         return s;
     }
 
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 2f87deb..b9d28e4 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -100,7 +100,8 @@
 message TaskRecordProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
+    // To be removed soon.
+    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
     optional int32 id = 2;
     repeated ActivityRecordProto activities = 3;
     optional int32 stack_id = 4;
@@ -113,6 +114,7 @@
     optional .android.graphics.RectProto bounds = 11;
     optional int32 min_width = 12;
     optional int32 min_height = 13;
+    optional .com.android.server.wm.TaskProto task = 14;
 }
 
 message ActivityRecordProto {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index d1c171a..4ed8f42 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -16,6 +16,11 @@
 
 package android.media.tv.tuner;
 
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
 import java.util.List;
 
 /**
@@ -34,8 +39,9 @@
         nativeInit();
     }
 
-    private FrontendCallback mFrontendCallback;
     private List<Integer> mFrontendIds;
+    private Frontend mFrontend;
+    private EventHandler mHandler;
 
     public Tuner() {
         nativeSetup();
@@ -80,11 +86,66 @@
         void onEvent(int frontendEventType);
     }
 
-    protected static class Frontend {
-        int mId;
+    @Nullable
+    private EventHandler createEventHandler() {
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            return new EventHandler(looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            return new EventHandler(looper);
+        }
+        return null;
+    }
+
+    private class EventHandler extends Handler {
+        private EventHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_FRONTEND_EVENT:
+                    if (mFrontend != null && mFrontend.mCallback != null) {
+                        mFrontend.mCallback.onEvent(msg.arg1);
+                    }
+                    break;
+                default:
+                    // fall through
+            }
+        }
+    }
+
+    protected class Frontend {
+        private int mId;
+        private FrontendCallback mCallback;
+
         private Frontend(int id) {
             mId = id;
         }
+
+        public void setCallback(@Nullable FrontendCallback callback, @Nullable Handler handler) {
+            mCallback = callback;
+
+            if (mCallback == null) {
+                return;
+            }
+
+            if (handler == null) {
+                // use default looper if handler is null
+                if (mHandler == null) {
+                    mHandler = createEventHandler();
+                }
+                return;
+            }
+
+            Looper looper = handler.getLooper();
+            if (mHandler != null && mHandler.getLooper() == looper) {
+                // the same looper. reuse mHandler
+                return;
+            }
+            mHandler = new EventHandler(looper);
+        }
     }
 
     private List<Integer> getFrontendIds() {
@@ -94,12 +155,19 @@
 
     private Frontend openFrontendById(int id) {
         if (mFrontendIds == null) {
-            getFrontendIds();
+            mFrontendIds = getFrontendIds();
         }
         if (!mFrontendIds.contains(id)) {
             return null;
         }
-        return nativeOpenFrontendById(id);
+        mFrontend = nativeOpenFrontendById(id);
+        return mFrontend;
+    }
+
+    private void onFrontendEvent(int eventType) {
+        if (mHandler != null) {
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_FRONTEND_EVENT, eventType, 0));
+        }
     }
 
     protected class Filter {
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 9e96b74..f815097 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -36,6 +36,7 @@
     jfieldID context;
     jmethodID frontendInitID;
     jmethodID filterInitID;
+    jmethodID onFrontendEventID;
 };
 
 static fields_t gFields;
@@ -52,7 +53,32 @@
     return Void();
 }
 
+/////////////// FrontendCallback ///////////////////////
+
+FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
+
+Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
+    ALOGD("FrontendCallback::onEvent, type=%d", frontendEventType);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(
+            mObject,
+            gFields.onFrontendEventID,
+            (jint)frontendEventType);
+    return Void();
+}
+Return<void> FrontendCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) {
+    ALOGD("FrontendCallback::onDiseqcMessage");
+    return Void();
+}
+
+Return<void> FrontendCallback::onScanMessage(
+        FrontendScanMessageType type, const FrontendScanMessage& /*message*/) {
+    ALOGD("FrontendCallback::onScanMessage, type=%d", type);
+    return Void();
+}
+
 /////////////// Tuner ///////////////////////
+
 sp<ITuner> JTuner::mTuner;
 
 JTuner::JTuner(JNIEnv *env, jobject thiz)
@@ -89,11 +115,10 @@
 
 jobject JTuner::getFrontendIds() {
     ALOGD("JTuner::getFrontendIds()");
-    hidl_vec<FrontendId> feIds;
     mTuner->getFrontendIds([&](Result, const hidl_vec<FrontendId>& frontendIds) {
-        feIds = frontendIds;
+        mFeIds = frontendIds;
     });
-    if (feIds.size() == 0) {
+    if (mFeIds.size() == 0) {
         ALOGW("Frontend isn't available");
         return NULL;
     }
@@ -106,21 +131,25 @@
     jclass integerClazz = env->FindClass("java/lang/Integer");
     jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
 
-    for (int i=0; i < feIds.size(); i++) {
-       jobject idObj = env->NewObject(integerClazz, intInit, feIds[i]);
+    for (int i=0; i < mFeIds.size(); i++) {
+       jobject idObj = env->NewObject(integerClazz, intInit, mFeIds[i]);
        env->CallBooleanMethod(obj, arrayListAdd, idObj);
     }
     return obj;
 }
 
 jobject JTuner::openFrontendById(int id) {
+    sp<IFrontend> fe;
     mTuner->openFrontendById(id, [&](Result, const sp<IFrontend>& frontend) {
-        mFe = frontend;
+        fe = frontend;
     });
-    if (mFe == nullptr) {
+    if (fe == nullptr) {
         ALOGE("Failed to open frontend");
         return NULL;
     }
+    mFe = fe;
+    sp<FrontendCallback> feCb = new FrontendCallback(mObject, id);
+    fe->setCallback(feCb);
 
     jint jId = (jint) id;
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -128,6 +157,7 @@
     return env->NewObject(
             env->FindClass("android/media/tv/tuner/Tuner$Frontend"),
             gFields.frontendInitID,
+            mObject,
             (jint) jId);
 }
 
@@ -210,8 +240,11 @@
     gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
     CHECK(gFields.context != NULL);
 
+    gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V");
+
     jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend");
-    gFields.frontendInitID = env->GetMethodID(frontendClazz, "<init>", "(I)V");
+    gFields.frontendInitID =
+            env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
 
     jclass filterClazz = env->FindClass("android/media/tv/tuner/Tuner$Filter");
     gFields.filterInitID =
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index b23b394..7a889c3 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -24,14 +24,19 @@
 #include "jni.h"
 
 using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using ::android::hardware::tv::tuner::V1_0::FrontendEventType;
 using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
+using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
 using ::android::hardware::tv::tuner::V1_0::IDemux;
 using ::android::hardware::tv::tuner::V1_0::IFilter;
 using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
 using ::android::hardware::tv::tuner::V1_0::IFrontend;
+using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
 
 namespace android {
@@ -41,6 +46,18 @@
     virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
 };
 
+struct FrontendCallback : public IFrontendCallback {
+    FrontendCallback(jweak tunerObj, FrontendId id);
+
+    virtual Return<void> onEvent(FrontendEventType frontendEventType);
+    virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
+    virtual Return<void> onScanMessage(
+            FrontendScanMessageType type, const FrontendScanMessage& message);
+
+    jweak mObject;
+    FrontendId mId;
+};
+
 struct JTuner : public RefBase {
     JTuner(JNIEnv *env, jobject thiz);
     sp<ITuner> getTunerService();
@@ -55,6 +72,7 @@
     jclass mClass;
     jweak mObject;
     static sp<ITuner> mTuner;
+    hidl_vec<FrontendId> mFeIds;
     sp<IFrontend> mFe;
     sp<IDemux> mDemux;
     int mDemuxId;
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 706727b..d3d9b28 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -16,100 +16,30 @@
 
 package com.android.systemui;
 
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.util.DisplayMetrics;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.assist.AssistManager;
 import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.doze.DozeLog;
 import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.navigationbar.car.CarNavigationBar;
-import com.android.systemui.navigationbar.car.CarNavigationBarController;
 import com.android.systemui.pip.PipUI;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsModule;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationViewHierarchyManager;
-import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.car.CarStatusBar;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.car.CarStatusBarModule;
 import com.android.systemui.statusbar.notification.InstantAppNotifier;
-import com.android.systemui.statusbar.notification.NewNotifPipeline;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.phone.AutoHideController;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.DozeScrimController;
-import com.android.systemui.statusbar.phone.DozeServiceHost;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.LockscreenWallpaper;
-import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.tv.TvStatusBar;
 import com.android.systemui.theme.ThemeOverlayController;
-import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.volume.VolumeUI;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import dagger.Binds;
-import dagger.Lazy;
 import dagger.Module;
-import dagger.Provides;
 import dagger.multibindings.ClassKey;
 import dagger.multibindings.IntoMap;
 
 /** Binder for car specific {@link SystemUI} modules. */
-@Module(includes = {RecentsModule.class})
+@Module(includes = {RecentsModule.class, CarStatusBarModule.class})
 public abstract class CarSystemUIBinder {
     /** Inject into AuthController. */
     @Binds
@@ -219,147 +149,4 @@
     @IntoMap
     @ClassKey(VolumeUI.class)
     public abstract SystemUI bindVolumeUI(VolumeUI sysui);
-
-    /**
-     * Provides our instance of StatusBar which is considered optional.
-     */
-    @Provides
-    @Singleton
-    static CarStatusBar provideStatusBar(
-            Context context,
-            FeatureFlags featureFlags,
-            LightBarController lightBarController,
-            AutoHideController autoHideController,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            StatusBarIconController statusBarIconController,
-            DozeLog dozeLog,
-            InjectionInflationController injectionInflationController,
-            PulseExpansionHandler pulseExpansionHandler,
-            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
-            KeyguardBypassController keyguardBypassController,
-            KeyguardStateController keyguardStateController,
-            HeadsUpManagerPhone headsUpManagerPhone,
-            DynamicPrivacyController dynamicPrivacyController,
-            BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
-            Lazy<NewNotifPipeline> newNotifPipeline,
-            FalsingManager falsingManager,
-            BroadcastDispatcher broadcastDispatcher,
-            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
-            NotificationGutsManager notificationGutsManager,
-            NotificationLogger notificationLogger,
-            NotificationEntryManager notificationEntryManager,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
-            NotificationViewHierarchyManager notificationViewHierarchyManager,
-            ForegroundServiceController foregroundServiceController,
-            AppOpsController appOpsController,
-            KeyguardViewMediator keyguardViewMediator,
-            ZenModeController zenModeController,
-            NotificationAlertingManager notificationAlertingManager,
-            DisplayMetrics displayMetrics,
-            MetricsLogger metricsLogger,
-            UiOffloadThread uiOffloadThread,
-            NotificationMediaManager notificationMediaManager,
-            NotificationLockscreenUserManager lockScreenUserManager,
-            NotificationRemoteInputManager remoteInputManager,
-            UserSwitcherController userSwitcherController,
-            NetworkController networkController,
-            BatteryController batteryController,
-            SysuiColorExtractor colorExtractor,
-            ScreenLifecycle screenLifecycle,
-            WakefulnessLifecycle wakefulnessLifecycle,
-            SysuiStatusBarStateController statusBarStateController,
-            VibratorHelper vibratorHelper,
-            BubbleController bubbleController,
-            NotificationGroupManager groupManager,
-            NotificationGroupAlertTransferHelper groupAlertTransferHelper,
-            VisualStabilityManager visualStabilityManager,
-            DeviceProvisionedController deviceProvisionedController,
-            NavigationBarController navigationBarController,
-            AssistManager assistManager,
-            NotificationListener notificationListener,
-            ConfigurationController configurationController,
-            StatusBarWindowController statusBarWindowController,
-            StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
-            NotifLog notifLog,
-            DozeParameters dozeParameters,
-            ScrimController scrimController,
-            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
-            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
-            DozeServiceHost dozeServiceHost,
-            PowerManager powerManager,
-            DozeScrimController dozeScrimController,
-            CommandQueue commandQueue,
-            PluginManager pluginManager,
-            CarNavigationBarController carNavigationBarController,
-            RemoteInputUriController remoteInputUriController) {
-        return new CarStatusBar(
-                context,
-                featureFlags,
-                lightBarController,
-                autoHideController,
-                keyguardUpdateMonitor,
-                statusBarIconController,
-                dozeLog,
-                injectionInflationController,
-                pulseExpansionHandler,
-                notificationWakeUpCoordinator,
-                keyguardBypassController,
-                keyguardStateController,
-                headsUpManagerPhone,
-                dynamicPrivacyController,
-                bypassHeadsUpNotifier,
-                allowNotificationLongPress,
-                newNotifPipeline,
-                falsingManager,
-                broadcastDispatcher,
-                remoteInputQuickSettingsDisabler,
-                notificationGutsManager,
-                notificationLogger,
-                notificationEntryManager,
-                notificationInterruptionStateProvider,
-                notificationViewHierarchyManager,
-                foregroundServiceController,
-                appOpsController,
-                keyguardViewMediator,
-                zenModeController,
-                notificationAlertingManager,
-                displayMetrics,
-                metricsLogger,
-                uiOffloadThread,
-                notificationMediaManager,
-                lockScreenUserManager,
-                remoteInputManager,
-                userSwitcherController,
-                networkController,
-                batteryController,
-                colorExtractor,
-                screenLifecycle,
-                wakefulnessLifecycle,
-                statusBarStateController,
-                vibratorHelper,
-                bubbleController,
-                groupManager,
-                groupAlertTransferHelper,
-                visualStabilityManager,
-                deviceProvisionedController,
-                navigationBarController,
-                assistManager,
-                notificationListener,
-                configurationController,
-                statusBarWindowController,
-                statusBarWindowViewControllerBuilder,
-                notifLog,
-                dozeParameters,
-                scrimController,
-                lockscreenWallpaperLazy,
-                biometricUnlockControllerLazy,
-                dozeServiceHost,
-                powerManager,
-                dozeScrimController,
-                commandQueue,
-                pluginManager,
-                remoteInputUriController,
-                carNavigationBarController);
-    }
 }
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 110b32b..fc0b317 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -92,6 +92,7 @@
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
@@ -131,7 +132,6 @@
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.InjectionInflationController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -244,7 +244,6 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             StatusBarIconController statusBarIconController,
             DozeLog dozeLog,
-            InjectionInflationController injectionInflationController,
             PulseExpansionHandler pulseExpansionHandler,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
@@ -303,6 +302,7 @@
             CommandQueue commandQueue,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
+            SuperStatusBarViewFactory superStatusBarViewFactory,
             /* Car Settings injected components. */
             CarNavigationBarController carNavigationBarController) {
         super(
@@ -313,7 +313,6 @@
                 keyguardUpdateMonitor,
                 statusBarIconController,
                 dozeLog,
-                injectionInflationController,
                 pulseExpansionHandler,
                 notificationWakeUpCoordinator,
                 keyguardBypassController,
@@ -372,7 +371,8 @@
                 dozeScrimController,
                 commandQueue,
                 pluginManager,
-                remoteInputUriController);
+                remoteInputUriController,
+                superStatusBarViewFactory);
         mScrimController = scrimController;
         mCarNavigationBarController = carNavigationBarController;
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
new file mode 100644
index 0000000..b19fae8
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car;
+
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.util.DisplayMetrics;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.UiOffloadThread;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.StatusBarDependenciesModule;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.DozeScrimController;
+import com.android.systemui.statusbar.phone.DozeServiceHost;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LockscreenWallpaper;
+import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module providing {@link CarStatusBar}.
+ */
+@Module(includes = {StatusBarDependenciesModule.class})
+public class CarStatusBarModule {
+    /**
+     * Provides our instance of StatusBar which is considered optional.
+     */
+    @Provides
+    @Singleton
+    static CarStatusBar provideStatusBar(
+            Context context,
+            FeatureFlags featureFlags,
+            LightBarController lightBarController,
+            AutoHideController autoHideController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            StatusBarIconController statusBarIconController,
+            DozeLog dozeLog,
+            PulseExpansionHandler pulseExpansionHandler,
+            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
+            KeyguardStateController keyguardStateController,
+            HeadsUpManagerPhone headsUpManagerPhone,
+            DynamicPrivacyController dynamicPrivacyController,
+            BypassHeadsUpNotifier bypassHeadsUpNotifier,
+            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
+            Lazy<NewNotifPipeline> newNotifPipeline,
+            FalsingManager falsingManager,
+            BroadcastDispatcher broadcastDispatcher,
+            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
+            NotificationGutsManager notificationGutsManager,
+            NotificationLogger notificationLogger,
+            NotificationEntryManager notificationEntryManager,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationViewHierarchyManager notificationViewHierarchyManager,
+            ForegroundServiceController foregroundServiceController,
+            AppOpsController appOpsController,
+            KeyguardViewMediator keyguardViewMediator,
+            ZenModeController zenModeController,
+            NotificationAlertingManager notificationAlertingManager,
+            DisplayMetrics displayMetrics,
+            MetricsLogger metricsLogger,
+            UiOffloadThread uiOffloadThread,
+            NotificationMediaManager notificationMediaManager,
+            NotificationLockscreenUserManager lockScreenUserManager,
+            NotificationRemoteInputManager remoteInputManager,
+            UserSwitcherController userSwitcherController,
+            NetworkController networkController,
+            BatteryController batteryController,
+            SysuiColorExtractor colorExtractor,
+            ScreenLifecycle screenLifecycle,
+            WakefulnessLifecycle wakefulnessLifecycle,
+            SysuiStatusBarStateController statusBarStateController,
+            VibratorHelper vibratorHelper,
+            BubbleController bubbleController,
+            NotificationGroupManager groupManager,
+            NotificationGroupAlertTransferHelper groupAlertTransferHelper,
+            VisualStabilityManager visualStabilityManager,
+            DeviceProvisionedController deviceProvisionedController,
+            NavigationBarController navigationBarController,
+            AssistManager assistManager,
+            NotificationListener notificationListener,
+            ConfigurationController configurationController,
+            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
+            NotifLog notifLog,
+            DozeParameters dozeParameters,
+            ScrimController scrimController,
+            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
+            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+            DozeServiceHost dozeServiceHost,
+            PowerManager powerManager,
+            DozeScrimController dozeScrimController,
+            CommandQueue commandQueue,
+            PluginManager pluginManager,
+            RemoteInputUriController remoteInputUriController,
+            SuperStatusBarViewFactory superStatusBarViewFactory,
+            CarNavigationBarController carNavigationBarController) {
+        return new CarStatusBar(
+                context,
+                featureFlags,
+                lightBarController,
+                autoHideController,
+                keyguardUpdateMonitor,
+                statusBarIconController,
+                dozeLog,
+                pulseExpansionHandler,
+                notificationWakeUpCoordinator,
+                keyguardBypassController,
+                keyguardStateController,
+                headsUpManagerPhone,
+                dynamicPrivacyController,
+                bypassHeadsUpNotifier,
+                allowNotificationLongPress,
+                newNotifPipeline,
+                falsingManager,
+                broadcastDispatcher,
+                remoteInputQuickSettingsDisabler,
+                notificationGutsManager,
+                notificationLogger,
+                notificationEntryManager,
+                notificationInterruptionStateProvider,
+                notificationViewHierarchyManager,
+                foregroundServiceController,
+                appOpsController,
+                keyguardViewMediator,
+                zenModeController,
+                notificationAlertingManager,
+                displayMetrics,
+                metricsLogger,
+                uiOffloadThread,
+                notificationMediaManager,
+                lockScreenUserManager,
+                remoteInputManager,
+                userSwitcherController,
+                networkController,
+                batteryController,
+                colorExtractor,
+                screenLifecycle,
+                wakefulnessLifecycle,
+                statusBarStateController,
+                vibratorHelper,
+                bubbleController,
+                groupManager,
+                groupAlertTransferHelper,
+                visualStabilityManager,
+                deviceProvisionedController,
+                navigationBarController,
+                assistManager,
+                notificationListener,
+                configurationController,
+                statusBarWindowController,
+                statusBarWindowViewControllerBuilder,
+                notifLog,
+                dozeParameters,
+                scrimController,
+                lockscreenWallpaperLazy,
+                biometricUnlockControllerLazy,
+                dozeServiceHost,
+                powerManager,
+                dozeScrimController,
+                commandQueue,
+                pluginManager,
+                remoteInputUriController,
+                superStatusBarViewFactory,
+                carNavigationBarController);
+    }
+}
diff --git a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
index 5dc9061..de45ea5 100644
--- a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
+++ b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
@@ -21,7 +21,6 @@
 import com.squareup.javapoet.JavaFile;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
 
 import java.io.IOException;
@@ -73,10 +72,12 @@
         }
         mRanOnce = true;
 
+        final ClassName searchIndexableData = ClassName.get(PACKAGE, "SearchIndexableData");
+
         final FieldSpec providers = FieldSpec.builder(
                 ParameterizedTypeName.get(
                         ClassName.get(Set.class),
-                        TypeName.get(Class.class)),
+                        searchIndexableData),
                 "mProviders",
                 Modifier.PRIVATE, Modifier.FINAL)
                 .initializer("new $T()", HashSet.class)
@@ -84,7 +85,7 @@
 
         final MethodSpec addIndex = MethodSpec.methodBuilder("addIndex")
                 .addModifiers(Modifier.PUBLIC)
-                .addParameter(ClassName.get(Class.class), "indexClass")
+                .addParameter(searchIndexableData, "indexClass")
                 .addCode("$N.add(indexClass);\n", providers)
                 .build();
 
@@ -113,19 +114,25 @@
                     SearchIndexable searchIndexable = element.getAnnotation(SearchIndexable.class);
 
                     int forTarget = searchIndexable.forTarget();
+                    MethodSpec.Builder builder = baseConstructorBuilder;
+
                     if (forTarget == SearchIndexable.ALL) {
-                        baseConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
+                        builder = baseConstructorBuilder;
                     } else if ((forTarget & SearchIndexable.MOBILE) != 0) {
-                        mobileConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
+                        builder = mobileConstructorBuilder;
                     } else if ((forTarget & SearchIndexable.TV) != 0) {
-                        tvConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
+                        builder = tvConstructorBuilder;
                     } else if ((forTarget & SearchIndexable.WEAR) != 0) {
-                        wearConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
+                        builder = wearConstructorBuilder;
                     } else if ((forTarget & SearchIndexable.AUTO) != 0) {
-                        autoConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
+                        builder = autoConstructorBuilder;
                     } else if ((forTarget & SearchIndexable.ARC) != 0) {
-                        arcConstructorBuilder.addCode("$N($L.class);\n", addIndex, className);
+                        builder = arcConstructorBuilder;
                     }
+                    builder.addCode(
+                            "$N(new SearchIndexableData($L.class, $L"
+                                    + ".SEARCH_INDEX_DATA_PROVIDER));\n",
+                            addIndex, className, className);
                 } else {
                     throw new IllegalStateException("Null classname from " + element);
                 }
@@ -137,7 +144,7 @@
                 .addModifiers(Modifier.PUBLIC)
                 .returns(ParameterizedTypeName.get(
                         ClassName.get(Collection.class),
-                        TypeName.get(Class.class)))
+                        searchIndexableData))
                 .addCode("return $N;\n", providers)
                 .build();
 
diff --git a/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableData.java b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableData.java
new file mode 100644
index 0000000..8b8f268
--- /dev/null
+++ b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableData.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.search;
+
+/**
+ * A Bundle class used in {@link SearchIndexableResources} to provide search Index data.
+ */
+public class SearchIndexableData {
+    private final Class mTargetClass;
+    private final Indexable.SearchIndexProvider mSearchIndexProvider;
+
+    /**
+     * Constructs a SearchIndexableData
+     *
+     * @param targetClass The target opening class of the {@link Indexable.SearchIndexProvider}. It
+     *                    should be a {@link android.app.Activity} or fragment {@link
+     *                    androidx.fragment.app.Fragment}.
+     *                    But fragment is only supported in Android Settings. Other apps should use
+     *                    {@link android.app.Activity}
+     * @param provider    provides searchable data for Android Settings
+     */
+    public SearchIndexableData(Class targetClass, Indexable.SearchIndexProvider provider) {
+        mTargetClass = targetClass;
+        mSearchIndexProvider = provider;
+    }
+
+    public Class getTargetClass() {
+        return mTargetClass;
+    }
+
+    public Indexable.SearchIndexProvider getSearchIndexProvider() {
+        return mSearchIndexProvider;
+    }
+}
diff --git a/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java
index 976647b..e00ca71 100644
--- a/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java
+++ b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java
@@ -21,15 +21,12 @@
 public interface SearchIndexableResources {
 
     /**
-     * Returns a collection of classes that should be indexed for search.
-     *
-     * Each class should have the SEARCH_INDEX_DATA_PROVIDER public static member.
+     * Returns a Collection of {@link SearchIndexableData} that should be indexed for search.
      */
-    Collection<Class> getProviderValues();
+    Collection<SearchIndexableData> getProviderValues();
 
     /**
-     * For testing. Can't use @VisibleForTesting here because this builds as a host binary as well
-     * as a device binary.
+     * Add {@link SearchIndexableData} for search in Android Settings.
      */
-    void addIndex(Class indexClass);
+    void addIndex(SearchIndexableData indexBundle);
 }
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 14371fe..64b2892 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1120,8 +1120,6 @@
     <dimen name="bubble_touch_padding">12dp</dimen>
     <!-- Size of the circle around the bubbles when they're in the dismiss target. -->
     <dimen name="bubble_dismiss_encircle_size">52dp</dimen>
-    <!-- How much to inset the icon in the circle -->
-    <dimen name="bubble_icon_inset">16dp</dimen>
     <!-- Padding around the view displayed when the bubble is expanded -->
     <dimen name="bubble_expanded_view_padding">4dp</dimen>
     <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 46b4c6b..21b52c1 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -169,12 +169,15 @@
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
         mSeparator = separator;
         mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
-        mSimSlotsNumber = ((TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE)).getSupportedModemCount();
+        mSimSlotsNumber = getTelephonyManager().getSupportedModemCount();
         mSimErrorState = new boolean[mSimSlotsNumber];
         mMainHandler = Dependency.get(Dependency.MAIN_HANDLER);
     }
 
+    private TelephonyManager getTelephonyManager() {
+        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
     /**
      * Checks if there are faulty cards. Adds the text depending on the slot of the card
      *
@@ -190,7 +193,7 @@
         CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
                 IccCardConstants.State.CARD_IO_ERROR, carrier);
         // mSimErrorState has the state of each sim indexed by slotID.
-        for (int index = 0; index < mSimErrorState.length; index++) {
+        for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) {
             if (!mSimErrorState[index]) {
                 continue;
             }
@@ -223,8 +226,7 @@
      * @param callback Callback to provide text updates
      */
     public void setListening(CarrierTextCallback callback) {
-        TelephonyManager telephonyManager = ((TelephonyManager) mContext
-                .getSystemService(Context.TELEPHONY_SERVICE));
+        TelephonyManager telephonyManager = getTelephonyManager();
         if (callback != null) {
             mCarrierTextCallback = callback;
             // TODO(b/140034799)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index f5f1fad..84a592d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -298,7 +298,10 @@
                     .getDimension(R.dimen.biometric_dialog_icon_padding);
             mIconView.setY(getHeight() - mIconView.getHeight() - iconPadding);
 
-            final int newHeight = mIconView.getHeight() + 2 * (int) iconPadding;
+            // Subtract the vertical padding from the new height since it's only used to create
+            // extra space between the other elements, and not part of the actual icon.
+            final int newHeight = mIconView.getHeight() + 2 * (int) iconPadding
+                    - mIconView.getPaddingTop() - mIconView.getPaddingBottom();
             mPanelController.updateForContentDimensions(mMediumWidth, newHeight,
                     0 /* animateDurationMs */);
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 516de70..6b0d3c8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -23,7 +23,10 @@
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.app.TaskStackListener;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.hardware.biometrics.Authenticator;
@@ -85,6 +88,28 @@
         }
     }
 
+    @VisibleForTesting
+    final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (mCurrentDialog != null
+                    && Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                Log.w(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received");
+                mCurrentDialog.dismissWithoutCallback(true /* animate */);
+                mCurrentDialog = null;
+
+                try {
+                    if (mReceiver != null) {
+                        mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                        mReceiver = null;
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Remote exception", e);
+                }
+            }
+        }
+    };
+
     private final Runnable mTaskStackChangedRunnable = () -> {
         if (mCurrentDialog != null) {
             try {
@@ -204,6 +229,11 @@
         super(context);
         mCommandQueue = commandQueue;
         mInjector = injector;
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+
+        context.registerReceiver(mBroadcastReceiver, filter);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 7600b2f..f8e45d4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -134,6 +134,10 @@
         return mAppName;
     }
 
+    public Drawable getUserBadgedAppIcon() {
+        return mUserBadgedAppIcon;
+    }
+
     boolean isInflated() {
         return mInflated;
     }
@@ -165,7 +169,6 @@
         mIconView = (BubbleView) inflater.inflate(
                 R.layout.bubble_view, stackView, false /* attachToRoot */);
         mIconView.setBubble(this);
-        mIconView.setAppIcon(mUserBadgedAppIcon);
 
         mExpandedView = (BubbleExpandedView) inflater.inflate(
                 R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index e5af389..4a1bbe4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1459,7 +1459,7 @@
             mFlyout.setupFlyoutStartingAsDot(
                     updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
                     mStackAnimationController.isStackOnLeftSide(),
-                    bubble.getIconView().getBadgeColor() /* dotColor */,
+                    bubble.getIconView().getDotColor() /* dotColor */,
                     expandFlyoutAfterDelay /* onLayoutComplete */,
                     mFlyoutOnHide,
                     bubble.getIconView().getDotCenter());
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index fe4fa90..35657d3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -24,17 +24,16 @@
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Path;
-import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.graphics.drawable.InsetDrawable;
 import android.util.AttributeSet;
 import android.util.PathParser;
 import android.widget.FrameLayout;
 
 import com.android.internal.graphics.ColorUtils;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.ColorExtractor;
 import com.android.launcher3.icons.ShadowGenerator;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -45,17 +44,13 @@
  */
 public class BubbleView extends FrameLayout {
 
-    private static final int DARK_ICON_ALPHA = 180;
-    private static final double ICON_MIN_CONTRAST = 4.1;
-    private static final int DEFAULT_BACKGROUND_COLOR = Color.LTGRAY;
     // Same value as Launcher3 badge code
     private static final float WHITE_SCRIM_ALPHA = 0.54f;
     private Context mContext;
 
     private BadgedImageView mBadgedImageView;
-    private int mBadgeColor;
-    private int mIconInset;
-    private Drawable mUserBadgedAppIcon;
+    private int mDotColor;
+    private ColorExtractor mColorExtractor;
 
     // mBubbleIconFactory cannot be static because it depends on Context.
     private BubbleIconFactory mBubbleIconFactory;
@@ -79,13 +74,13 @@
     public BubbleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         mContext = context;
-        mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mBadgedImageView = findViewById(R.id.bubble_image);
+        mColorExtractor = new ColorExtractor();
     }
 
     @Override
@@ -106,6 +101,13 @@
     }
 
     /**
+     * @param factory Factory for creating normalized bubble icons.
+     */
+    public void setBubbleIconFactory(BubbleIconFactory factory) {
+        mBubbleIconFactory = factory;
+    }
+
+    /**
      * The {@link NotificationEntry} associated with this view, if one exists.
      */
     @Nullable
@@ -129,17 +131,6 @@
         updateViews();
     }
 
-    /**
-     * @param factory Factory for creating normalized bubble icons.
-     */
-    public void setBubbleIconFactory(BubbleIconFactory factory) {
-        mBubbleIconFactory = factory;
-    }
-
-    public void setAppIcon(Drawable appIcon) {
-        mUserBadgedAppIcon = appIcon;
-    }
-
     /** Changes the dot's visibility to match the bubble view's state. */
     void updateDotVisibility(boolean animate) {
         updateDotVisibility(animate, null /* after */);
@@ -154,9 +145,17 @@
         updateDotVisibility(animate);
     }
 
+    boolean isDotShowing() {
+        return mBubble.showBubbleDot() && !mSuppressDot;
+    }
+
+    int getDotColor() {
+        return mDotColor;
+    }
+
     /** Sets the position of the 'new' dot, animating it out and back in if requested. */
     void setDotPosition(boolean onLeft, boolean animate) {
-        if (animate && onLeft != mBadgedImageView.getDotOnLeft() && shouldShowDot()) {
+        if (animate && onLeft != mBadgedImageView.getDotOnLeft() && isDotShowing()) {
             animateDot(false /* showDot */, () -> {
                 mBadgedImageView.setDotOnLeft(onLeft);
                 animateDot(true /* showDot */, null);
@@ -180,7 +179,7 @@
      * after animation if requested.
      */
     private void updateDotVisibility(boolean animate, Runnable after) {
-        final boolean showDot = shouldShowDot();
+        final boolean showDot = isDotShowing();
         if (animate) {
             animateDot(showDot, after);
         } else {
@@ -218,42 +217,21 @@
         if (mBubble == null || mBubbleIconFactory == null) {
             return;
         }
-        // Update icon.
-        Notification.BubbleMetadata metadata = mBubble.getEntry().getBubbleMetadata();
-        Notification n = mBubble.getEntry().getSbn().getNotification();
-        Icon ic = metadata.getIcon();
-        boolean needsTint = ic.getType() != Icon.TYPE_ADAPTIVE_BITMAP;
 
-        Drawable iconDrawable = ic.loadDrawable(mContext);
-        if (needsTint) {
-            iconDrawable = buildIconWithTint(iconDrawable, n.color);
-        }
-        Bitmap bubbleIcon = mBubbleIconFactory.createBadgedIconBitmap(iconDrawable,
-                null /* user */,
-                true /* shrinkNonAdaptiveIcons */).icon;
-
-        // Give it a shadow
-        Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap(mUserBadgedAppIcon,
-                1f, mBubbleIconFactory.getBadgeSize());
-        Canvas c = new Canvas();
-        ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize());
-        c.setBitmap(userBadgedBitmap);
-        shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
-
-        mBubbleIconFactory.badgeWithDrawable(bubbleIcon,
-                new BitmapDrawable(mContext.getResources(), userBadgedBitmap));
-        mBadgedImageView.setImageBitmap(bubbleIcon);
+        Drawable bubbleDrawable = getBubbleDrawable(mContext);
+        BitmapInfo badgeBitmapInfo = getBadgedBitmap();
+        BitmapInfo bubbleBitmapInfo = getBubbleBitmap(bubbleDrawable, badgeBitmapInfo);
+        mBadgedImageView.setImageBitmap(bubbleBitmapInfo.icon);
 
         // Update badge.
-        int badgeColor = determineDominateColor(iconDrawable, n.color);
-        mBadgeColor = badgeColor;
-        mBadgedImageView.setDotColor(badgeColor);
+        mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA);
+        mBadgedImageView.setDotColor(mDotColor);
 
         // Update dot.
         Path iconPath = PathParser.createPathFromPathData(
                 getResources().getString(com.android.internal.R.string.config_icon_mask));
         Matrix matrix = new Matrix();
-        float scale = mBubbleIconFactory.getNormalizer().getScale(iconDrawable,
+        float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable,
                 null /* outBounds */, null /* path */, null /* outMaskShape */);
         float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f;
         matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
@@ -261,41 +239,34 @@
         iconPath.transform(matrix);
         mBadgedImageView.drawDot(iconPath);
 
-        animateDot(shouldShowDot(), null /* after */);
+        animateDot(isDotShowing(), null /* after */);
     }
 
-    boolean shouldShowDot() {
-        return mBubble.showBubbleDot() && !mSuppressDot;
+    Drawable getBubbleDrawable(Context context) {
+        Notification.BubbleMetadata metadata = getEntry().getBubbleMetadata();
+        Icon ic = metadata.getIcon();
+        return ic.loadDrawable(context);
     }
 
-    int getBadgeColor() {
-        return mBadgeColor;
+    BitmapInfo getBadgedBitmap() {
+        Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap(
+                mBubble.getUserBadgedAppIcon(), 1f, mBubbleIconFactory.getBadgeSize());
+
+        Canvas c = new Canvas();
+        ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize());
+        c.setBitmap(userBadgedBitmap);
+        shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
+        BitmapInfo bitmapInfo = mBubbleIconFactory.createIconBitmap(userBadgedBitmap);
+        return bitmapInfo;
     }
 
-    private AdaptiveIconDrawable buildIconWithTint(Drawable iconDrawable, int backgroundColor) {
-        iconDrawable = checkTint(iconDrawable, backgroundColor);
-        InsetDrawable foreground = new InsetDrawable(iconDrawable, mIconInset);
-        ColorDrawable background = new ColorDrawable(backgroundColor);
-        return new AdaptiveIconDrawable(background, foreground);
-    }
+    BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) {
+        BitmapInfo bubbleIconInfo = mBubbleIconFactory.createBadgedIconBitmap(bubble,
+                null /* user */,
+                true /* shrinkNonAdaptiveIcons */);
 
-    private Drawable checkTint(Drawable iconDrawable, int backgroundColor) {
-        backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 255 /* alpha */);
-        if (backgroundColor == Color.TRANSPARENT) {
-            // ColorUtils throws exception when background is translucent.
-            backgroundColor = DEFAULT_BACKGROUND_COLOR;
-        }
-        iconDrawable.setTint(Color.WHITE);
-        double contrastRatio = ColorUtils.calculateContrast(Color.WHITE, backgroundColor);
-        if (contrastRatio < ICON_MIN_CONTRAST) {
-            int dark = ColorUtils.setAlphaComponent(Color.BLACK, DARK_ICON_ALPHA);
-            iconDrawable.setTint(dark);
-        }
-        return iconDrawable;
-    }
-
-    private int determineDominateColor(Drawable d, int defaultTint) {
-        // XXX: should we pull from the drawable, app icon, notif tint?
-        return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA);
+        mBubbleIconFactory.badgeWithDrawable(bubbleIconInfo.icon,
+                new BitmapDrawable(mContext.getResources(), badge.icon));
+        return bubbleIconInfo;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 3b0c9ae..9f54937 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -16,109 +16,35 @@
 
 package com.android.systemui.dagger;
 
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.util.DisplayMetrics;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.LatencyTester;
 import com.android.systemui.ScreenDecorations;
 import com.android.systemui.SizeCompatModeActivityController;
 import com.android.systemui.SliceBroadcastRelayHandler;
 import com.android.systemui.SystemUI;
-import com.android.systemui.UiOffloadThread;
-import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.assist.AssistManager;
 import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.doze.DozeLog;
 import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.pip.PipUI;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsModule;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationViewHierarchyManager;
-import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.InstantAppNotifier;
-import com.android.systemui.statusbar.notification.NewNotifPipeline;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.phone.AutoHideController;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.DozeScrimController;
-import com.android.systemui.statusbar.phone.DozeServiceHost;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
-import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.LockscreenWallpaper;
-import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.phone.StatusBarModule;
 import com.android.systemui.statusbar.tv.TvStatusBar;
 import com.android.systemui.theme.ThemeOverlayController;
-import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.volume.VolumeUI;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import dagger.Binds;
-import dagger.Lazy;
 import dagger.Module;
-import dagger.Provides;
 import dagger.multibindings.ClassKey;
 import dagger.multibindings.IntoMap;
 
 /**
  * SystemUI objects that are injectable should go here.
  */
-@Module(includes = {RecentsModule.class})
+@Module(includes = {RecentsModule.class, StatusBarModule.class})
 public abstract class SystemUIBinder {
     /** Inject into AuthController. */
     @Binds
@@ -216,148 +142,4 @@
     @IntoMap
     @ClassKey(VolumeUI.class)
     public abstract SystemUI bindVolumeUI(VolumeUI sysui);
-
-    /**
-     * Provides our instance of StatusBar which is considered optional.
-     */
-    @Provides
-    @Singleton
-    static StatusBar provideStatusBar(
-            Context context,
-            FeatureFlags featureFlags,
-            LightBarController lightBarController,
-            AutoHideController autoHideController,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            StatusBarIconController statusBarIconController,
-            DozeLog dozeLog,
-            InjectionInflationController injectionInflationController,
-            PulseExpansionHandler pulseExpansionHandler,
-            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
-            KeyguardBypassController keyguardBypassController,
-            KeyguardStateController keyguardStateController,
-            HeadsUpManagerPhone headsUpManagerPhone,
-            DynamicPrivacyController dynamicPrivacyController,
-            BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
-            Lazy<NewNotifPipeline> newNotifPipeline,
-            FalsingManager falsingManager,
-            BroadcastDispatcher broadcastDispatcher,
-            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
-            NotificationGutsManager notificationGutsManager,
-            NotificationLogger notificationLogger,
-            NotificationEntryManager notificationEntryManager,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
-            NotificationViewHierarchyManager notificationViewHierarchyManager,
-            ForegroundServiceController foregroundServiceController,
-            AppOpsController appOpsController,
-            KeyguardViewMediator keyguardViewMediator,
-            ZenModeController zenModeController,
-            NotificationAlertingManager notificationAlertingManager,
-            DisplayMetrics displayMetrics,
-            MetricsLogger metricsLogger,
-            UiOffloadThread uiOffloadThread,
-            NotificationMediaManager notificationMediaManager,
-            NotificationLockscreenUserManager lockScreenUserManager,
-            NotificationRemoteInputManager remoteInputManager,
-            UserSwitcherController userSwitcherController,
-            NetworkController networkController,
-            BatteryController batteryController,
-            SysuiColorExtractor colorExtractor,
-            ScreenLifecycle screenLifecycle,
-            WakefulnessLifecycle wakefulnessLifecycle,
-            SysuiStatusBarStateController statusBarStateController,
-            VibratorHelper vibratorHelper,
-            BubbleController bubbleController,
-            NotificationGroupManager groupManager,
-            NotificationGroupAlertTransferHelper groupAlertTransferHelper,
-            VisualStabilityManager visualStabilityManager,
-            DeviceProvisionedController deviceProvisionedController,
-            NavigationBarController navigationBarController,
-            AssistManager assistManager,
-            NotificationListener notificationListener,
-            ConfigurationController configurationController,
-            StatusBarWindowController statusBarWindowController,
-            StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
-            NotifLog notifLog,
-            DozeParameters dozeParameters,
-            ScrimController scrimController,
-            @Nullable KeyguardLiftController keyguardLiftController,
-            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
-            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
-            DozeServiceHost dozeServiceHost,
-            PowerManager powerManager,
-            DozeScrimController dozeScrimController,
-            CommandQueue commandQueue,
-            PluginManager pluginManager,
-            RemoteInputUriController remoteInputUriController) {
-        return new StatusBar(
-                context,
-                featureFlags,
-                lightBarController,
-                autoHideController,
-                keyguardUpdateMonitor,
-                statusBarIconController,
-                dozeLog,
-                injectionInflationController,
-                pulseExpansionHandler,
-                notificationWakeUpCoordinator,
-                keyguardBypassController,
-                keyguardStateController,
-                headsUpManagerPhone,
-                dynamicPrivacyController,
-                bypassHeadsUpNotifier,
-                allowNotificationLongPress,
-                newNotifPipeline,
-                falsingManager,
-                broadcastDispatcher,
-                remoteInputQuickSettingsDisabler,
-                notificationGutsManager,
-                notificationLogger,
-                notificationEntryManager,
-                notificationInterruptionStateProvider,
-                notificationViewHierarchyManager,
-                foregroundServiceController,
-                appOpsController,
-                keyguardViewMediator,
-                zenModeController,
-                notificationAlertingManager,
-                displayMetrics,
-                metricsLogger,
-                uiOffloadThread,
-                notificationMediaManager,
-                lockScreenUserManager,
-                remoteInputManager,
-                userSwitcherController,
-                networkController,
-                batteryController,
-                colorExtractor,
-                screenLifecycle,
-                wakefulnessLifecycle,
-                statusBarStateController,
-                vibratorHelper,
-                bubbleController,
-                groupManager,
-                groupAlertTransferHelper,
-                visualStabilityManager,
-                deviceProvisionedController,
-                navigationBarController,
-                assistManager,
-                notificationListener,
-                configurationController,
-                statusBarWindowController,
-                statusBarWindowViewControllerBuilder,
-                notifLog,
-                dozeParameters,
-                scrimController,
-                keyguardLiftController,
-                lockscreenWallpaperLazy,
-                biometricUnlockControllerLazy,
-                dozeServiceHost,
-                powerManager,
-                dozeScrimController,
-                commandQueue,
-                pluginManager,
-                remoteInputUriController);
-    }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 9e7f6c6..b3a5181 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -25,6 +25,7 @@
 import com.android.systemui.assist.AssistModule;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.people.PeopleHubModule;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -71,5 +72,8 @@
     }
 
     @BindsOptionalOf
+    abstract CommandQueue optionalCommandQueue();
+
+    @BindsOptionalOf
     abstract StatusBar optionalStatusBar();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 264d644..4635884 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -101,6 +101,7 @@
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -109,6 +110,7 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
 
 /**
  * POD used in the AsyncTask which saves an image in the background.
@@ -1041,8 +1043,9 @@
         private final StatusBar mStatusBar;
 
         @Inject
-        public ActionProxyReceiver(StatusBar statusBar) {
-            mStatusBar = statusBar;
+        public ActionProxyReceiver(Optional<Lazy<StatusBar>> statusBarLazy) {
+            Lazy<StatusBar> statusBar = statusBarLazy.orElse(null);
+            mStatusBar = statusBar != null ? statusBar.get() : null;
         }
 
         @Override
@@ -1067,8 +1070,13 @@
                 context.startActivityAsUser(actionIntent, opts.toBundle(), UserHandle.CURRENT);
             };
 
-            mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null,
-                    true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
+            if (mStatusBar != null) {
+                mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null,
+                        true /* dismissShade */, true /* afterKeyguardGone */,
+                        true /* deferred */);
+            } else {
+                startActivityRunnable.run();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index eb6ea13..b723b75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -50,8 +50,6 @@
 import android.view.View;
 import android.view.WindowInsetsController.Appearance;
 
-import androidx.annotation.VisibleForTesting;
-
 import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
@@ -61,9 +59,6 @@
 
 import java.util.ArrayList;
 
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
 /**
  * This class takes the functions from IStatusBar that come in on
  * binder pool threads and posts messages to get them onto the main
@@ -71,7 +66,6 @@
  * coalescing these calls so they don't stack up.  For the calls
  * are coalesced, note that they are all idempotent.
  */
-@Singleton
 public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks>,
         DisplayManager.DisplayListener {
     private static final int INDEX_MASK = 0xffff;
@@ -307,8 +301,6 @@
         }
     }
 
-    @VisibleForTesting
-    @Inject
     public CommandQueue(Context context) {
         context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler);
         // We always have default display.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
new file mode 100644
index 0000000..48f02cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module providing common dependencies of StatusBar.
+ */
+@Module
+public class StatusBarDependenciesModule {
+    /**
+     * Provides our instance of CommandQueue which is considered optional.
+     */
+    @Provides
+    public CommandQueue provideCommandQueue(Context context) {
+        return new CommandQueue(context);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java
new file mode 100644
index 0000000..bc7c22d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import com.android.systemui.util.InjectionInflationController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Creates a single instance of super_status_bar that can be shared across various system ui
+ * objects.
+ */
+@Singleton
+public class SuperStatusBarViewFactory {
+
+    private final Context mContext;
+    private final InjectionInflationController mInjectionInflationController;
+
+    private StatusBarWindowView mStatusBarWindowView;
+    private NotificationShelf mNotificationShelf;
+
+    @Inject
+    public SuperStatusBarViewFactory(Context context,
+            InjectionInflationController injectionInflationController) {
+        mContext = context;
+        mInjectionInflationController = injectionInflationController;
+    }
+
+    /**
+     * Gets the inflated {@link StatusBarWindowView} from {@link R.layout#super_status_bar}. Returns
+     * a cached instance, if it has already been inflated.
+     */
+    public StatusBarWindowView getStatusBarWindowView() {
+        if (mStatusBarWindowView != null) {
+            return mStatusBarWindowView;
+        }
+
+        mStatusBarWindowView = (StatusBarWindowView) mInjectionInflationController.injectable(
+                LayoutInflater.from(mContext)).inflate(R.layout.super_status_bar,
+                /* root= */ null);
+        if (mStatusBarWindowView == null) {
+            throw new IllegalStateException(
+                    "R.layout.super_status_bar could not be properly inflated");
+        }
+        return mStatusBarWindowView;
+    }
+
+    /**
+     * Gets the inflated {@link NotificationShelf} from
+     * {@link R.layout#status_bar_notification_shelf}.
+     * Returns a cached instance, if it has already been inflated.
+     *
+     * @param container the expected container to hold the {@link NotificationShelf}. The view
+     *                  isn't immediately attached, but the layout params of this view is used
+     *                  during inflation.
+     */
+    public NotificationShelf getNotificationShelf(ViewGroup container) {
+        if (mNotificationShelf != null) {
+            return mNotificationShelf;
+        }
+
+        mNotificationShelf = (NotificationShelf) mInjectionInflationController.injectable(
+                LayoutInflater.from(mContext)).inflate(R.layout.status_bar_notification_shelf,
+                container, /* attachToRoot= */ false);
+        if (mNotificationShelf == null) {
+            throw new IllegalStateException(
+                    "R.layout.status_bar_notification_shelf could not be properly inflated");
+        }
+        return mNotificationShelf;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index a817f54..50a2037 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -159,6 +159,8 @@
     private int mHeadsUpAddStartLocation;
     private float mHeadsUpLocation;
     private boolean mIsAppearing;
+    private boolean mDismissed;
+    private boolean mRefocusOnDismiss;
 
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -1048,6 +1050,27 @@
         return getHeight();
     }
 
+    /** Mark that this view has been dismissed. */
+    public void dismiss(boolean refocusOnDismiss) {
+        mDismissed = true;
+        mRefocusOnDismiss = refocusOnDismiss;
+    }
+
+    /** Mark that this view is no longer dismissed. */
+    public void unDismiss() {
+        mDismissed = false;
+    }
+
+    /** Is this view marked as dismissed? */
+    public boolean isDismissed() {
+        return mDismissed;
+    }
+
+    /** Should a re-focus occur upon dismissing this view? */
+    public boolean shouldRefocusOnDismiss() {
+        return mRefocusOnDismiss || isAccessibilityFocused();
+    }
+
     public interface OnActivatedListener {
         void onActivated(ActivatableNotificationView view);
         void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 536db67..f0d07a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -95,6 +95,7 @@
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.SwipeableView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -114,7 +115,7 @@
  * the group summary (which contains 1 or more child notifications).
  */
 public class ExpandableNotificationRow extends ActivatableNotificationView
-        implements PluginListener<NotificationMenuRowPlugin> {
+        implements PluginListener<NotificationMenuRowPlugin>, SwipeableView {
 
     private static final boolean DEBUG = false;
     private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
@@ -288,7 +289,6 @@
         }
     };
     private boolean mForceUnlocked;
-    private boolean mDismissed;
     private boolean mKeepInParent;
     private boolean mRemoved;
     private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
@@ -307,7 +307,6 @@
     private boolean mHeadsupDisappearRunning;
     private View mChildAfterViewWhenDismissed;
     private View mGroupParentWhenDismissed;
-    private boolean mRefocusOnDismiss;
     private float mContentTransformationAmount;
     private boolean mIconsVisible = true;
     private boolean mAboveShelf;
@@ -1164,6 +1163,11 @@
         }
     }
 
+    @Override
+    public boolean hasFinishedInitialization() {
+        return getEntry().hasFinishedInitialization();
+    }
+
     /**
      * Get a handle to a NotificationMenuRowPlugin whose menu view has been added to our hierarchy,
      * or null if there is no menu row
@@ -1323,11 +1327,11 @@
         }
     }
 
-    public void setDismissed(boolean fromAccessibility) {
+    @Override
+    public void dismiss(boolean refocusOnDismiss) {
+        super.dismiss(refocusOnDismiss);
         setLongPressListener(null);
-        mDismissed = true;
         mGroupParentWhenDismissed = mNotificationParent;
-        mRefocusOnDismiss = fromAccessibility;
         mChildAfterViewWhenDismissed = null;
         mEntry.icon.setDismissed();
         if (isChildInGroup()) {
@@ -1340,10 +1344,6 @@
         }
     }
 
-    public boolean isDismissed() {
-        return mDismissed;
-    }
-
     public boolean keepInParent() {
         return mKeepInParent;
     }
@@ -1445,7 +1445,7 @@
                 groupSummary.getRow().performDismiss(fromAccessibility);
             }
         }
-        setDismissed(fromAccessibility);
+        dismiss(fromAccessibility);
         if (mEntry.isClearable()) {
             // TODO: beverlyt, log dismissal
             // TODO: track dismiss sentiment
@@ -3021,10 +3021,6 @@
         return false;
     }
 
-    public boolean shouldRefocusOnDismiss() {
-        return mRefocusOnDismiss || isAccessibilityFocused();
-    }
-
     public interface OnExpandClickListener {
         void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 54d4066..fdd51e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -23,7 +23,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.PendingIntent;
 import android.content.Intent;
 import android.provider.Settings;
 import android.view.LayoutInflater;
@@ -310,6 +309,8 @@
                 mParent.removeView(mPeopleHubView);
             }
         } else {
+            mPeopleHubView.unDismiss();
+            mPeopleHubView.resetTranslation();
             if (!currentlyVisible) {
                 if (mPeopleHubView.getTransientContainer() != null) {
                     mPeopleHubView.getTransientContainer().removeTransientView(mPeopleHubView);
@@ -419,8 +420,9 @@
         }
     }
 
-    private void handlePeopleHubClick(PendingIntent pendingIntent) {
-        mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent, null, mPeopleHubView);
+    void hidePeopleRow() {
+        mPeopleHubVisible = false;
+        updateSectionBoundaries();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 6dca7ee..2b9912c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -4920,7 +4920,7 @@
             } else {
                 child.setMinClipTopAmount(0);
             }
-            previousChildWillBeDismissed = StackScrollAlgorithm.canChildBeDismissed(child);
+            previousChildWillBeDismissed = canChildBeDismissed(child);
         }
     }
 
@@ -5523,7 +5523,7 @@
 
         performDismissAllAnimations(viewsToHide, closeShade, () -> {
             for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
-                if (StackScrollAlgorithm.canChildBeDismissed(rowToRemove)) {
+                if (canChildBeDismissed(rowToRemove)) {
                     if (selection == ROWS_ALL) {
                         // TODO: This is a listener method; we shouldn't be calling it. Can we just
                         // call performRemoveNotification as below?
@@ -5552,7 +5552,7 @@
     private boolean includeChildInDismissAll(
             ExpandableNotificationRow row,
             @SelectedRows int selection) {
-        return StackScrollAlgorithm.canChildBeDismissed(row) && matchesSelection(row, selection);
+        return canChildBeDismissed(row) && matchesSelection(row, selection);
     }
 
     /**
@@ -6223,7 +6223,10 @@
          */
         @Override
         public void onChildDismissed(View view) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            if (!(view instanceof ActivatableNotificationView)) {
+                return;
+            }
+            ActivatableNotificationView row = (ActivatableNotificationView) view;
             if (!row.isDismissed()) {
                 handleChildViewDismissed(view);
             }
@@ -6261,6 +6264,12 @@
                         row.performDismissWithBlockingHelper(false /* fromAccessibility */);
             }
 
+            if (view instanceof PeopleHubView) {
+                PeopleHubView row = (PeopleHubView) view;
+                row.dismiss(false);
+                mSectionsManager.hidePeopleRow();
+            }
+
             if (!isBlockingHelperShown) {
                 mSwipedOutViews.add(view);
             }
@@ -6349,9 +6358,9 @@
             return 0;
         }
 
-                @Override
+        @Override
         public boolean canChildBeDismissed(View v) {
-            return StackScrollAlgorithm.canChildBeDismissed(v);
+            return NotificationStackScrollLayout.canChildBeDismissed(v);
         }
 
         @Override
@@ -6361,6 +6370,23 @@
         }
     };
 
+    private static boolean canChildBeDismissed(View v) {
+        if (v instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+            if (row.isBlockingHelperShowingAndTranslationFinished()) {
+                return true;
+            }
+            if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) {
+                return false;
+            }
+            return row.canViewBeDismissed();
+        }
+        if (v instanceof PeopleHubView) {
+            return true;
+        }
+        return false;
+    }
+
     // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
 
     @ShadeViewRefactor(RefactorComponent.INPUT)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 0968674..6d0fcc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -31,11 +31,10 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
-class NotificationSwipeHelper extends SwipeHelper
-        implements NotificationSwipeActionHelper {
+class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
+
     @VisibleForTesting
     protected static final long COVER_MENU_DELAY = 4000;
     private static final String TAG = "NotificationSwipeHelper";
@@ -58,12 +57,7 @@
         super(swipeDirection, callback, context, falsingManager);
         mMenuListener = menuListener;
         mCallback = callback;
-        mFalsingCheck = new Runnable() {
-            @Override
-            public void run() {
-                resetExposedMenuView(true /* animate */, true /* force */);
-            }
-        };
+        mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
     }
 
     public View getTranslatingParentView() {
@@ -126,14 +120,14 @@
         // Slide back any notifications that might be showing a menu
         resetExposedMenuView(true /* animate */, false /* force */);
 
-        if (currView instanceof ExpandableNotificationRow) {
-            initializeRow((ExpandableNotificationRow) currView);
+        if (currView instanceof SwipeableView) {
+            initializeRow((SwipeableView) currView);
         }
     }
 
     @VisibleForTesting
-    protected void initializeRow(ExpandableNotificationRow row) {
-        if (row.getEntry().hasFinishedInitialization()) {
+    protected void initializeRow(SwipeableView row) {
+        if (row.hasFinishedInitialization()) {
             mCurrMenuRow = row.createMenu();
             if (mCurrMenuRow != null) {
                 mCurrMenuRow.setMenuClickListener(mMenuListener);
@@ -304,8 +298,8 @@
     @Override
     public Animator getViewTranslationAnimator(View v, float target,
             ValueAnimator.AnimatorUpdateListener listener) {
-        if (v instanceof ExpandableNotificationRow) {
-            return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
+        if (v instanceof SwipeableView) {
+            return ((SwipeableView) v).getTranslateViewAnimator(target, listener);
         } else {
             return superGetViewTranslationAnimator(v, target, listener);
         }
@@ -313,15 +307,15 @@
 
     @Override
     public void setTranslation(View v, float translate) {
-        if (v instanceof ExpandableNotificationRow) {
-            ((ExpandableNotificationRow) v).setTranslation(translate);
+        if (v instanceof SwipeableView) {
+            ((SwipeableView) v).setTranslation(translate);
         }
     }
 
     @Override
     public float getTranslation(View v) {
-        if (v instanceof ExpandableNotificationRow) {
-            return ((ExpandableNotificationRow) v).getTranslation();
+        if (v instanceof SwipeableView) {
+            return ((SwipeableView) v).getTranslation();
         }
         else {
             return 0f;
@@ -410,8 +404,8 @@
             if (anim != null) {
                 anim.start();
             }
-        } else if (prevMenuExposedView instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) prevMenuExposedView;
+        } else if (prevMenuExposedView instanceof SwipeableView) {
+            SwipeableView row = (SwipeableView) prevMenuExposedView;
             if (!row.isRemoved()) {
                 row.resetTranslation();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index e31ee02..a079606 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -16,23 +16,39 @@
 
 package com.android.systemui.statusbar.notification.stack
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
 import android.content.Context
 import android.util.AttributeSet
+import android.util.FloatProperty
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.TextView
 import com.android.systemui.R
-import com.android.systemui.statusbar.notification.people.PersonViewModel
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
 import com.android.systemui.statusbar.notification.people.DataListener
+import com.android.systemui.statusbar.notification.people.PersonViewModel
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
 
+private val TRANSLATE_CONTENT = object : FloatProperty<PeopleHubView>("translate") {
+    override fun setValue(view: PeopleHubView, value: Float) {
+        view.translation = value
+    }
+
+    override fun get(view: PeopleHubView) = view.translation
+}
+
 class PeopleHubView(context: Context, attrs: AttributeSet) :
-        ActivatableNotificationView(context, attrs) {
+        ActivatableNotificationView(context, attrs), SwipeableView {
 
     private lateinit var contents: ViewGroup
     private lateinit var personControllers: List<PersonDataListenerImpl>
+    private var translateAnim: ObjectAnimator? = null
+
     val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
         get() = personControllers.asSequence()
 
@@ -49,6 +65,34 @@
 
     override fun getContentView(): View = contents
 
+    override fun hasFinishedInitialization(): Boolean = true
+
+    override fun createMenu(): NotificationMenuRowPlugin? = null
+
+    override fun getTranslateViewAnimator(
+        leftTarget: Float,
+        listener: ValueAnimator.AnimatorUpdateListener?
+    ): Animator =
+            ObjectAnimator
+                    .ofFloat(this, TRANSLATE_CONTENT, leftTarget)
+                    .apply {
+                        listener?.let { addUpdateListener(listener) }
+                        addListener(object : AnimatorListenerAdapter() {
+                            override fun onAnimationEnd(anim: Animator) {
+                                translateAnim = null
+                            }
+                        })
+                    }
+                    .also {
+                        translateAnim?.cancel()
+                        translateAnim = it
+                    }
+
+    override fun resetTranslation() {
+        translateAnim?.cancel()
+        translationX = 0f
+    }
+
     private inner class PersonDataListenerImpl(val viewGroup: ViewGroup) :
             DataListener<PersonViewModel?> {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 4b61064..9646c01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -195,20 +195,6 @@
         }
     }
 
-    public static boolean canChildBeDismissed(View v) {
-        if (!(v instanceof ExpandableNotificationRow)) {
-            return false;
-        }
-        ExpandableNotificationRow row = (ExpandableNotificationRow) v;
-        if (row.isBlockingHelperShowingAndTranslationFinished()) {
-            return true;
-        }
-        if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) {
-            return false;
-        }
-        return row.canViewBeDismissed();
-    }
-
     /**
      * Updates the dimmed, activated and hiding sensitive states of the children.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
new file mode 100644
index 0000000..6c6ef61
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+
+/** A View that is swipeable inside of the notification shade. */
+public interface SwipeableView {
+
+    /** Has this view finished initializing? */
+    boolean hasFinishedInitialization();
+
+    /** Optionally creates a menu for this view. */
+    @Nullable NotificationMenuRowPlugin createMenu();
+
+    /** Animator for translating the view, simulating a swipe. */
+    Animator getTranslateViewAnimator(
+            float leftTarget, ValueAnimator.AnimatorUpdateListener listener);
+
+    /** Sets the translation amount for an in-progress swipe. */
+    void setTranslation(float translate);
+
+    /** Gets the current translation amount. */
+    float getTranslation();
+
+    /** Has this view been removed? */
+    boolean isRemoved();
+
+    /** Resets the swipe translation back to zero state. */
+    void resetTranslation();
+}
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 4148a73..b0104d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -75,7 +75,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.media.AudioAttributes;
@@ -109,7 +108,6 @@
 import android.view.IWindowManager;
 import android.view.InsetsState.InternalInsetType;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.RemoteAnimationAdapter;
 import android.view.ThreadedRenderer;
@@ -157,7 +155,6 @@
 import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.dagger.SystemUIBinder;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.fragments.ExtensionFragmentListener;
@@ -202,6 +199,7 @@
 import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
@@ -243,7 +241,6 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
@@ -364,8 +361,6 @@
     @Nullable
     private final KeyguardLiftController mKeyguardLiftController;
 
-    private int mNaturalBarHeight = -1;
-
     private final Point mCurrentDisplaySize = new Point();
 
     protected StatusBarWindowViewController mStatusBarWindowViewController;
@@ -384,7 +379,6 @@
     private final FeatureFlags mFeatureFlags;
     private final StatusBarIconController mIconController;
     private final DozeLog mDozeLog;
-    private final InjectionInflationController mInjectionInflater;
     private final PulseExpansionHandler mPulseExpansionHandler;
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
     private final KeyguardBypassController mKeyguardBypassController;
@@ -403,6 +397,7 @@
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     private final PluginManager mPluginManager;
     private final RemoteInputUriController mRemoteInputUriController;
+    private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
 
     // expanded notifications
     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -637,7 +632,7 @@
      * Public constructor for StatusBar.
      *
      * StatusBar is considered optional, and therefore can not be marked as @Inject directly.
-     * Instead, an @Provide method is included in {@link SystemUIBinder}.
+     * Instead, an @Provide method is included.
      */
     public StatusBar(
             Context context,
@@ -647,7 +642,6 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             StatusBarIconController statusBarIconController,
             DozeLog dozeLog,
-            InjectionInflationController injectionInflationController,
             PulseExpansionHandler pulseExpansionHandler,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
@@ -706,7 +700,8 @@
             DozeScrimController dozeScrimController,
             CommandQueue commandQueue,
             PluginManager pluginManager,
-            RemoteInputUriController remoteInputUriController) {
+            RemoteInputUriController remoteInputUriController,
+            SuperStatusBarViewFactory superStatusBarViewFactory) {
         super(context);
         mFeatureFlags = featureFlags;
         mLightBarController = lightBarController;
@@ -714,7 +709,6 @@
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mIconController = statusBarIconController;
         mDozeLog = dozeLog;
-        mInjectionInflater = injectionInflationController;
         mPulseExpansionHandler = pulseExpansionHandler;
         mWakeUpCoordinator = notificationWakeUpCoordinator;
         mKeyguardBypassController = keyguardBypassController;
@@ -774,6 +768,8 @@
         mCommandQueue = commandQueue;
         mPluginManager = pluginManager;
         mRemoteInputUriController = remoteInputUriController;
+        mSuperStatusBarViewFactory = superStatusBarViewFactory;
+
         mBubbleExpandListener =
                 (isExpanding, key) -> {
                     mEntryManager.updateNotifications("onBubbleExpandChanged");
@@ -1368,10 +1364,7 @@
     }
 
     private void inflateShelf() {
-        mNotificationShelf =
-                (NotificationShelf) mInjectionInflater.injectable(
-                        LayoutInflater.from(mContext)).inflate(
-                                R.layout.status_bar_notification_shelf, mStackScroller, false);
+        mNotificationShelf = mSuperStatusBarViewFactory.getNotificationShelf(mStackScroller);
         mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
     }
 
@@ -1429,10 +1422,8 @@
     }
 
     protected void inflateStatusBarWindow(Context context) {
-        mStatusBarWindow = (StatusBarWindowView) mInjectionInflater.injectable(
-                LayoutInflater.from(context)).inflate(R.layout.super_status_bar, null);
+        mStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView();
         mStatusBarWindowViewController = mStatusBarWindowViewControllerBuilder
-                .setStatusBarWindowView(mStatusBarWindow)
                 .setShadeController(this)
                 .build();
     }
@@ -1470,12 +1461,7 @@
     }
 
     public int getStatusBarHeight() {
-        if (mNaturalBarHeight < 0) {
-            final Resources res = mContext.getResources();
-            mNaturalBarHeight =
-                    res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-        }
-        return mNaturalBarHeight;
+        return mStatusBarWindowController.getStatusBarHeight();
     }
 
     protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
@@ -2649,7 +2635,7 @@
 
     public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
         makeStatusBarView(result);
-        mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());
+        mStatusBarWindowController.attach();
     }
 
     // called by makeStatusbar and also by PhoneStatusBarView
@@ -2927,7 +2913,7 @@
             mQSPanel.updateResources();
         }
 
-        loadDimens();
+        mStatusBarWindowController.refreshStatusBarHeight();
 
         if (mStatusBarView != null) {
             mStatusBarView.updateResources();
@@ -2940,19 +2926,6 @@
         }
     }
 
-    protected void loadDimens() {
-        final Resources res = mContext.getResources();
-
-        int oldBarHeight = mNaturalBarHeight;
-        mNaturalBarHeight = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.status_bar_height);
-        if (mStatusBarWindowController != null && mNaturalBarHeight != oldBarHeight) {
-            mStatusBarWindowController.setBarHeight(mNaturalBarHeight);
-        }
-
-        if (DEBUG) Log.v(TAG, "defineSlots");
-    }
-
     // Visibility reporting
 
     protected void handleVisibleToUserChanged(boolean visibleToUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
new file mode 100644
index 0000000..67f6a0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.util.DisplayMetrics;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.UiOffloadThread;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.StatusBarDependenciesModule;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module providing {@link StatusBar}.
+ */
+@Module(includes = {StatusBarDependenciesModule.class})
+public class StatusBarModule {
+    /**
+     * Provides our instance of StatusBar which is considered optional.
+     */
+    @Provides
+    @Singleton
+    static StatusBar provideStatusBar(
+            Context context,
+            FeatureFlags featureFlags,
+            LightBarController lightBarController,
+            AutoHideController autoHideController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            StatusBarIconController statusBarIconController,
+            DozeLog dozeLog,
+            PulseExpansionHandler pulseExpansionHandler,
+            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
+            KeyguardStateController keyguardStateController,
+            HeadsUpManagerPhone headsUpManagerPhone,
+            DynamicPrivacyController dynamicPrivacyController,
+            BypassHeadsUpNotifier bypassHeadsUpNotifier,
+            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
+            Lazy<NewNotifPipeline> newNotifPipeline,
+            FalsingManager falsingManager,
+            BroadcastDispatcher broadcastDispatcher,
+            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
+            NotificationGutsManager notificationGutsManager,
+            NotificationLogger notificationLogger,
+            NotificationEntryManager notificationEntryManager,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationViewHierarchyManager notificationViewHierarchyManager,
+            ForegroundServiceController foregroundServiceController,
+            AppOpsController appOpsController,
+            KeyguardViewMediator keyguardViewMediator,
+            ZenModeController zenModeController,
+            NotificationAlertingManager notificationAlertingManager,
+            DisplayMetrics displayMetrics,
+            MetricsLogger metricsLogger,
+            UiOffloadThread uiOffloadThread,
+            NotificationMediaManager notificationMediaManager,
+            NotificationLockscreenUserManager lockScreenUserManager,
+            NotificationRemoteInputManager remoteInputManager,
+            UserSwitcherController userSwitcherController,
+            NetworkController networkController,
+            BatteryController batteryController,
+            SysuiColorExtractor colorExtractor,
+            ScreenLifecycle screenLifecycle,
+            WakefulnessLifecycle wakefulnessLifecycle,
+            SysuiStatusBarStateController statusBarStateController,
+            VibratorHelper vibratorHelper,
+            BubbleController bubbleController,
+            NotificationGroupManager groupManager,
+            NotificationGroupAlertTransferHelper groupAlertTransferHelper,
+            VisualStabilityManager visualStabilityManager,
+            DeviceProvisionedController deviceProvisionedController,
+            NavigationBarController navigationBarController,
+            AssistManager assistManager,
+            NotificationListener notificationListener,
+            ConfigurationController configurationController,
+            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
+            NotifLog notifLog,
+            DozeParameters dozeParameters,
+            ScrimController scrimController,
+            @Nullable KeyguardLiftController keyguardLiftController,
+            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
+            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+            DozeServiceHost dozeServiceHost,
+            PowerManager powerManager,
+            DozeScrimController dozeScrimController,
+            CommandQueue commandQueue,
+            PluginManager pluginManager,
+            RemoteInputUriController remoteInputUriController,
+            SuperStatusBarViewFactory superStatusBarViewFactory) {
+        return new StatusBar(
+                context,
+                featureFlags,
+                lightBarController,
+                autoHideController,
+                keyguardUpdateMonitor,
+                statusBarIconController,
+                dozeLog,
+                pulseExpansionHandler,
+                notificationWakeUpCoordinator,
+                keyguardBypassController,
+                keyguardStateController,
+                headsUpManagerPhone,
+                dynamicPrivacyController,
+                bypassHeadsUpNotifier,
+                allowNotificationLongPress,
+                newNotifPipeline,
+                falsingManager,
+                broadcastDispatcher,
+                remoteInputQuickSettingsDisabler,
+                notificationGutsManager,
+                notificationLogger,
+                notificationEntryManager,
+                notificationInterruptionStateProvider,
+                notificationViewHierarchyManager,
+                foregroundServiceController,
+                appOpsController,
+                keyguardViewMediator,
+                zenModeController,
+                notificationAlertingManager,
+                displayMetrics,
+                metricsLogger,
+                uiOffloadThread,
+                notificationMediaManager,
+                lockScreenUserManager,
+                remoteInputManager,
+                userSwitcherController,
+                networkController,
+                batteryController,
+                colorExtractor,
+                screenLifecycle,
+                wakefulnessLifecycle,
+                statusBarStateController,
+                vibratorHelper,
+                bubbleController,
+                groupManager,
+                groupAlertTransferHelper,
+                visualStabilityManager,
+                deviceProvisionedController,
+                navigationBarController,
+                assistManager,
+                notificationListener,
+                configurationController,
+                statusBarWindowController,
+                statusBarWindowViewControllerBuilder,
+                notifLog,
+                dozeParameters,
+                scrimController,
+                keyguardLiftController,
+                lockscreenWallpaperLazy,
+                biometricUnlockControllerLazy,
+                dozeServiceHost,
+                powerManager,
+                dozeScrimController,
+                commandQueue,
+                pluginManager,
+                remoteInputUriController,
+                superStatusBarViewFactory);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index ca7a936..2ecceba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -41,11 +41,13 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.MainResources;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.RemoteInputController.Callback;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -69,6 +71,7 @@
 public class StatusBarWindowController implements Callback, Dumpable, ConfigurationListener {
 
     private static final String TAG = "StatusBarWindowController";
+    private static final boolean DEBUG = false;
 
     private final Context mContext;
     private final WindowManager mWindowManager;
@@ -83,7 +86,7 @@
     private LayoutParams mLp;
     private boolean mHasTopUi;
     private boolean mHasTopUiChanged;
-    private int mBarHeight;
+    private int mBarHeight = -1;
     private float mScreenBrightnessDoze;
     private final State mCurrentState = new State();
     private OtherwisedCollapsedListener mListener;
@@ -92,13 +95,17 @@
             mCallbacks = Lists.newArrayList();
 
     private final SysuiColorExtractor mColorExtractor;
+    private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+    private final Resources mResources;
 
     @Inject
     public StatusBarWindowController(Context context, WindowManager windowManager,
             IActivityManager activityManager, DozeParameters dozeParameters,
             StatusBarStateController statusBarStateController,
             ConfigurationController configurationController,
-            KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor) {
+            KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor,
+            SuperStatusBarViewFactory superStatusBarViewFactory,
+            @MainResources Resources resources) {
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
@@ -108,6 +115,15 @@
         mLpChanged = new LayoutParams();
         mKeyguardBypassController = keyguardBypassController;
         mColorExtractor = colorExtractor;
+        mSuperStatusBarViewFactory = superStatusBarViewFactory;
+        mStatusBarView = mSuperStatusBarViewFactory.getStatusBarWindowView();
+        mResources = resources;
+
+        if (mBarHeight < 0) {
+            mBarHeight = mResources.getDimensionPixelSize(
+                    com.android.internal.R.dimen.status_bar_height);
+        }
+
         mLockScreenDisplayTimeout = context.getResources()
                 .getInteger(R.integer.config_lockScreenDisplayTimeout);
         ((SysuiStatusBarStateController) statusBarStateController)
@@ -149,20 +165,36 @@
                 || res.getBoolean(R.bool.config_enableLockScreenRotation);
     }
 
+    public int getStatusBarHeight() {
+        return mBarHeight;
+    }
+
+    /**
+     * Rereads the status_bar_height from configuration and reapplys the current state if the height
+     * is different.
+     */
+    public void refreshStatusBarHeight() {
+        int heightFromConfig = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+
+        if (mBarHeight != heightFromConfig) {
+            mBarHeight = heightFromConfig;
+            apply(mCurrentState);
+        }
+
+        if (DEBUG) Log.v(TAG, "defineSlots");
+    }
+
     /**
      * Adds the status bar view to the window manager.
-     *
-     * @param statusBarView The view to add.
-     * @param barHeight The height of the status bar in collapsed state.
      */
-    public void add(ViewGroup statusBarView, int barHeight) {
-
+    public void attach() {
         // Now that the status bar window encompasses the sliding panel and its
         // translucent backdrop, the entire thing is made TRANSLUCENT and is
         // hardware-accelerated.
         mLp = new LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
-                barHeight,
+                mBarHeight,
                 LayoutParams.TYPE_STATUS_BAR,
                 LayoutParams.FLAG_NOT_FOCUSABLE
                         | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
@@ -176,8 +208,6 @@
         mLp.setTitle("StatusBar");
         mLp.packageName = mContext.getPackageName();
         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        mStatusBarView = statusBarView;
-        mBarHeight = barHeight;
         mWindowManager.addView(mStatusBarView, mLp);
         mLpChanged.copyFrom(mLp);
         onThemeChanged();
@@ -534,11 +564,6 @@
         apply(mCurrentState);
     }
 
-    public void setBarHeight(int barHeight) {
-        mBarHeight = barHeight;
-        apply(mCurrentState);
-    }
-
     public void setForcePluginOpen(boolean forcePluginOpen) {
         mCurrentState.forcePluginOpen = forcePluginOpen;
         apply(mCurrentState);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index b7ada5d..f716443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -492,7 +493,8 @@
         private final DozeLog mDozeLog;
         private final DozeParameters mDozeParameters;
         private final CommandQueue mCommandQueue;
-        private StatusBarWindowView mView;
+        private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+        private final StatusBarWindowView mView;
 
         @Inject
         public Builder(
@@ -510,7 +512,8 @@
                 StatusBarStateController statusBarStateController,
                 DozeLog dozeLog,
                 DozeParameters dozeParameters,
-                CommandQueue commandQueue) {
+                CommandQueue commandQueue,
+                SuperStatusBarViewFactory superStatusBarViewFactory) {
             mInjectionInflationController = injectionInflationController;
             mCoordinator = coordinator;
             mPulseExpansionHandler = pulseExpansionHandler;
@@ -526,14 +529,9 @@
             mDozeLog = dozeLog;
             mDozeParameters = dozeParameters;
             mCommandQueue = commandQueue;
-        }
+            mSuperStatusBarViewFactory = superStatusBarViewFactory;
 
-        /**
-         * Provide {@link StatusBarWindowView} to attach this controller to.
-         */
-        public Builder setStatusBarWindowView(StatusBarWindowView view) {
-            mView = view;
-            return this;
+            mView = mSuperStatusBarViewFactory.getStatusBarWindowView();
         }
 
         /**
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 1dd4863..d8eaaa1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -145,6 +145,7 @@
         mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("",
                 new CharSequence[]{}, false, new int[]{});
         when(mTelephonyManager.getSupportedModemCount()).thenReturn(3);
+        when(mTelephonyManager.getActiveModemCount()).thenReturn(3);
 
         mCarrierTextController = new CarrierTextController(mContext, SEPARATOR, true, true);
         // This should not start listening on any of the real dependencies but will test that
@@ -216,6 +217,15 @@
         // There's only one subscription in the list
         assertEquals(1, captor.getValue().listOfCarriers.length);
         assertEquals(TEST_CARRIER, captor.getValue().listOfCarriers[0]);
+
+        // Now it becomes single SIM active mode.
+        reset(mCarrierTextCallback);
+        when(mTelephonyManager.getActiveModemCount()).thenReturn(1);
+        // Update carrier text. It should ignore error state of subId 3 in inactive slotId.
+        mCarrierTextController.updateCarrierText();
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals("TEST_CARRIER", captor.getValue().carrierText);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index c215a43..486fa12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -35,6 +35,7 @@
 import android.app.IActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.hardware.biometrics.Authenticator;
@@ -403,6 +404,19 @@
         mAuthController.onDeviceCredentialPressed();
     }
 
+    @Test
+    public void testActionCloseSystemDialogs_dismissesDialogIfShowing() throws Exception {
+        showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
+        Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        mAuthController.mBroadcastReceiver.onReceive(mContext, intent);
+        waitForIdleSync();
+
+        assertNull(mAuthController.mCurrentDialog);
+        assertNull(mAuthController.mReceiver);
+        verify(mDialog1).dismissWithoutCallback(true /* animate */);
+        verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL));
+    }
+
     // Helpers
 
     private void showDialog(int authenticators, int biometricModality) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 0068113..b1a6bc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -46,18 +46,19 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.hardware.face.FaceManager;
 import android.service.notification.ZenModeConfig;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.WindowManager;
-import android.widget.FrameLayout;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -65,6 +66,7 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -81,6 +83,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -119,7 +122,6 @@
     @Mock
     private KeyguardBypassController mKeyguardBypassController;
 
-    private FrameLayout mStatusBarView;
     @Captor
     private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
     @Captor
@@ -147,22 +149,28 @@
     private SysuiColorExtractor mColorExtractor;
     @Mock
     ColorExtractor.GradientColors mGradientColors;
+    @Mock
+    private Resources mResources;
 
+    private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     private BubbleData mBubbleData;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mStatusBarView = new FrameLayout(mContext);
         mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
         mContext.addMockSystemService(FaceManager.class, mFaceManager);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
+        mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
+                new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()));
+
         // Bubbles get added to status bar window view
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
                 mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController, mColorExtractor);
-        mStatusBarWindowController.add(mStatusBarView, 120 /* height */);
+                mConfigurationController, mKeyguardBypassController, mColorExtractor,
+                mSuperStatusBarViewFactory, mResources);
+        mStatusBarWindowController.attach();
 
         // Need notifications for bubbles
         mNotificationTestHelper = new NotificationTestHelper(mContext, mDependency);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 5e6c963..d17c573 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -226,7 +226,7 @@
                 any(NotificationMenuRowPlugin.MenuItem.class));
         reset(listener);
 
-        mGroupRow.setDismissed(true);
+        mGroupRow.dismiss(true);
         mGroupRow.doLongClickCallback(0,0);
         verify(listener, times(0)).onLongPress(eq(mGroupRow), eq(0), eq(0),
                 any(NotificationMenuRowPlugin.MenuItem.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index c21e3ab..ecb2d81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -107,6 +107,7 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -134,7 +135,6 @@
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -208,7 +208,6 @@
     @Mock private PulseExpansionHandler mPulseExpansionHandler;
     @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
     @Mock private KeyguardBypassController mKeyguardBypassController;
-    @Mock private InjectionInflationController mInjectionInflationController;
     @Mock private DynamicPrivacyController mDynamicPrivacyController;
     @Mock private NewNotifPipeline mNewNotifPipeline;
     @Mock private ZenModeController mZenModeController;
@@ -234,6 +233,7 @@
     @Mock private KeyguardLiftController mKeyguardLiftController;
     @Mock private CommandQueue mCommandQueue;
     @Mock private PluginManager mPluginManager;
+    @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
 
     @Before
     public void setup() throws Exception {
@@ -309,7 +309,6 @@
                 mKeyguardUpdateMonitor,
                 mStatusBarIconController,
                 mDozeLog,
-                mInjectionInflationController,
                 mPulseExpansionHandler,
                 mNotificationWakeUpCoordinator,
                 mKeyguardBypassController,
@@ -372,7 +371,8 @@
                 mDozeScrimController,
                 mCommandQueue,
                 mPluginManager,
-                mRemoteInputUriController);
+                mRemoteInputUriController,
+                mSuperStatusBarViewFactory);
 
         when(mStatusBarWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
                 mLockIconContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index a21a658..147edf6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -25,9 +25,9 @@
 import static org.mockito.Mockito.when;
 
 import android.app.IActivityManager;
+import android.content.res.Resources;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
-import android.view.ViewGroup;
 import android.view.WindowManager;
 
 import androidx.test.filters.SmallTest;
@@ -35,6 +35,7 @@
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
@@ -52,13 +53,15 @@
 
     @Mock private WindowManager mWindowManager;
     @Mock private DozeParameters mDozeParameters;
-    @Mock private ViewGroup mStatusBarView;
+    @Mock private StatusBarWindowView mStatusBarView;
     @Mock private IActivityManager mActivityManager;
     @Mock private SysuiStatusBarStateController mStatusBarStateController;
     @Mock private ConfigurationController mConfigurationController;
     @Mock private KeyguardBypassController mKeyguardBypassController;
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock ColorExtractor.GradientColors mGradientColors;
+    @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+    @Mock private Resources mResources;
 
     private StatusBarWindowController mStatusBarWindowController;
 
@@ -67,11 +70,14 @@
         MockitoAnnotations.initMocks(this);
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
+        when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mStatusBarView);
 
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
                 mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController, mColorExtractor);
-        mStatusBarWindowController.add(mStatusBarView, 100 /* height */);
+                mConfigurationController, mKeyguardBypassController, mColorExtractor,
+                mSuperStatusBarViewFactory, mResources);
+
+        mStatusBarWindowController.attach();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 20fb659..bf81325 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -35,6 +35,7 @@
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -72,6 +73,7 @@
     @Mock private StatusBar mStatusBar;
     @Mock private DozeLog mDozeLog;
     @Mock private DozeParameters mDozeParameters;
+    @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
 
     @Before
     public void setUp() {
@@ -82,6 +84,8 @@
         when(mStatusBar.isDozing()).thenReturn(false);
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
 
+        when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mView);
+
         mController = new StatusBarWindowViewController.Builder(
                 new InjectionInflationController(
                         SystemUIFactory.getInstance().getRootComponent()),
@@ -98,9 +102,9 @@
                 mStatusBarStateController,
                 mDozeLog,
                 mDozeParameters,
-                new CommandQueue(mContext))
+                new CommandQueue(mContext),
+                mSuperStatusBarViewFactory)
                 .setShadeController(mShadeController)
-                .setStatusBarWindowView(mView)
                 .build();
         mController.setService(mStatusBar);
         mController.setDragDownHelper(mDragDownHelper);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 48a7b73..1268113 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -41,7 +41,6 @@
 import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
 import static com.android.server.am.ActivityDisplayProto.STACKS;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
@@ -1523,7 +1522,7 @@
             final ActivityStack stack = getChildAt(i);
             final ArrayList<TaskRecord> tasks = stack.getAllTasks();
             for (int j = tasks.size() - 1; j >= 0; --j) {
-                stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING);
+                stack.removeChild(tasks.get(j), "removeAllTasks");
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index db219fd..d360041 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1148,56 +1148,11 @@
         }
     }
 
-    // TODO(task-unify): Remove once TaskRecord and Task are unified.
     TaskRecord getTaskRecord() {
         return task;
     }
 
     /**
-     * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent.
-     * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord}
-     * children. However, this method will clean up references to this {@link ActivityRecord} in
-     * {@link ActivityStack}.
-     * @param task The new parent {@link TaskRecord}.
-     */
-    // TODO(task-unify): Can be remove after task level unification. Callers can just use addChild
-    void setTask(TaskRecord task) {
-        // Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}.
-        if (task != null && task == getTaskRecord()) {
-            return;
-        }
-
-        final ActivityStack oldStack = getActivityStack();
-        final ActivityStack newStack = task != null ? task.getStack() : null;
-
-        // Inform old stack (if present) of activity removal and new stack (if set) of activity
-        // addition.
-        if (oldStack != newStack) {
-            if (oldStack != null) {
-                oldStack.onActivityRemovedFromStack(this);
-            }
-
-            if (newStack != null) {
-                newStack.onActivityAddedToStack(this);
-            }
-        }
-
-        final TaskRecord oldTask = this.task;
-        this.task = task;
-
-        // This is attaching the activity to the task which we only want to do once.
-        // TODO(task-unify): Need to re-work after unifying the task level since it will already
-        // have a parent then. Just need to restructure the re-parent case not to do this. NOTE that
-        // the reparenting flag passed in can't be used directly for this as it isn't set in
-        // ActivityRecord#reparent() case that ends up calling this method.
-        if (task != null && getParent() == null) {
-            task.addChild(this);
-        } else {
-            onParentChanged(task, oldTask);
-        }
-    }
-
-    /**
      * Sets the Task on this activity for the purposes of re-use during launch where we will
      * re-use another activity instead of this one for the launch.
      */
@@ -1220,8 +1175,8 @@
 
     @Override
     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        final TaskRecord oldTask = (oldParent != null) ? ((Task) oldParent).mTaskRecord : null;
-        final TaskRecord newTask = (newParent != null) ? ((Task) newParent).mTaskRecord : null;
+        final TaskRecord oldTask = oldParent != null ? (TaskRecord) oldParent : null;
+        final TaskRecord newTask = newParent != null ? (TaskRecord) newParent : null;
         this.task = newTask;
 
         super.onParentChanged(newParent, oldParent);
@@ -1230,14 +1185,12 @@
 
         if (oldParent == null && newParent != null) {
             // First time we are adding the activity to the system.
-            // TODO(task-unify): See if mVoiceInteraction variable is really needed after task level
-            // unification.
-            mVoiceInteraction = task.mTaskRecord != null && task.mTaskRecord.voiceSession != null;
+            mVoiceInteraction = newTask.voiceSession != null;
             mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L;
             onDisplayChanged(task.getDisplayContent());
-            if (task.mTaskRecord != null) {
-                task.mTaskRecord.updateOverrideConfigurationFromLaunchBounds();
-            }
+            // TODO(b/36505427): Maybe this call should be moved inside
+            // updateOverrideConfiguration()
+            newTask.updateOverrideConfigurationFromLaunchBounds();
             // Make sure override configuration is up-to-date before using to create window
             // controller.
             updateSizeCompatMode();
@@ -1279,8 +1232,6 @@
         // Inform old stack (if present) of activity removal and new stack (if set) of activity
         // addition.
         if (oldStack != newStack) {
-            // TODO(task-unify): Might be better to use onChildAdded and onChildRemoved signal for
-            // this once task level is unified.
             if (oldStack !=  null) {
                 oldStack.onActivityRemovedFromStack(this);
             }
@@ -1964,15 +1915,7 @@
 
         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s"
                 + " to task=%d at %d", this, task.mTaskId, position);
-
-        reparent(newTask.getTask(), position);
-    }
-
-    // TODO(task-unify): Remove once Task level is unified.
-    void onParentChanged(TaskRecord newParent, TaskRecord oldParent) {
-        onParentChanged(
-                newParent != null ? newParent.mTask : null,
-                oldParent != null ? oldParent.mTask : null);
+        reparent(newTask, position);
     }
 
     private boolean isHomeIntent(Intent intent) {
@@ -2051,7 +1994,7 @@
     /**
      * @return Stack value from current task, null if there is no task.
      */
-    // TODO: Remove once ActivityStack and TaskStack are unified.
+    // TODO(stack-unify): Remove once ActivityStack and TaskStack are unified.
     <T extends ActivityStack> T getActivityStack() {
         return task != null ? (T) task.getStack() : null;
     }
@@ -2339,7 +2282,7 @@
 
     /** Finish all activities in the task with the same affinity as this one. */
     void finishActivityAffinity() {
-        final ArrayList<ActivityRecord> activities = getTaskRecord().mActivities;
+        final ArrayList<ActivityRecord> activities = getTaskRecord().mChildren;
         for (int index = activities.indexOf(this); index >= 0; --index) {
             final ActivityRecord cur = activities.get(index);
             if (!Objects.equals(cur.taskAffinity, taskAffinity)) {
@@ -2451,7 +2394,7 @@
             EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                     mUserId, System.identityHashCode(this),
                     task.mTaskId, shortComponentName, reason);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final ArrayList<ActivityRecord> activities = task.mChildren;
             final int index = activities.indexOf(this);
             if (index < (task.getChildCount() - 1)) {
                 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
@@ -2505,7 +2448,7 @@
                 // When finishing the activity preemptively take the snapshot before the app window
                 // is marked as hidden and any configuration changes take place
                 if (mAtmService.mWindowManager.mTaskSnapshotController != null) {
-                    final ArraySet<Task> tasks = Sets.newArraySet(task.mTask);
+                    final ArraySet<Task> tasks = Sets.newArraySet(task);
                     mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
                     mAtmService.mWindowManager.mTaskSnapshotController
                             .addSkipClosingAppSnapshotTasks(tasks);
@@ -2547,7 +2490,8 @@
                 // In this case, we can set the visibility of all the task overlay activities when
                 // we detect the last one is finishing to keep them in sync.
                 if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
-                    for (ActivityRecord taskOverlay : task.mActivities) {
+                    for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
+                        final ActivityRecord taskOverlay = task.getChildAt(i);
                         if (!taskOverlay.mTaskOverlay) {
                             continue;
                         }
@@ -2819,8 +2763,6 @@
     }
 
     /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */
-    // TODO(task-unify): Look into consolidating this with TaskRecord.removeChild once we unify
-    // task level.
     void removeFromHistory(String reason) {
         finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */);
         makeFinishingLocked();
@@ -4668,7 +4610,7 @@
         }
 
         // Check if position in task allows to become paused
-        final int positionInTask = task.mActivities.indexOf(this);
+        final int positionInTask = task.mChildren.indexOf(this);
         if (positionInTask == -1) {
             throw new IllegalStateException("Activity not found in its task");
         }
@@ -5396,7 +5338,7 @@
             return INVALID_TASK_ID;
         }
         final TaskRecord task = r.task;
-        final int activityNdx = task.mActivities.indexOf(r);
+        final int activityNdx = task.mChildren.indexOf(r);
         if (activityNdx < 0
                 || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
             return INVALID_TASK_ID;
@@ -5760,7 +5702,7 @@
     @Override
     boolean isWaitingForTransitionStart() {
         final DisplayContent dc = getDisplayContent();
-        // TODO: Test for null can be removed once unification is done.
+        // TODO(display-unify): Test for null can be removed once unification is done.
         if (dc == null) return false;
         return dc.mAppTransition.isTransitionSet()
                 && (dc.mOpeningApps.contains(this)
@@ -6568,8 +6510,7 @@
                 // If the changes come from change-listener, the incoming parent configuration is
                 // still the old one. Make sure their orientations are the same to reduce computing
                 // the compatibility bounds for the intermediate state.
-                && (task.mTaskRecord == null || task.mTaskRecord
-                .getConfiguration().orientation == newParentConfig.orientation)) {
+                && (task.getConfiguration().orientation == newParentConfig.orientation)) {
             final Rect taskBounds = task.getBounds();
             // Since we only center the activity horizontally, if only the fixed height is smaller
             // than its container, the override bounds don't need to take effect.
@@ -6887,8 +6828,7 @@
             preserveWindow &= isResizeOnlyChange(changes);
             final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
             if (hasResizeChange) {
-                final boolean isDragResizing =
-                        getTaskRecord().getTask().isDragResizing();
+                final boolean isDragResizing = getTaskRecord().isDragResizing();
                 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE
                         : RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
             } else {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index edf8789..593318d 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -254,7 +254,11 @@
     @Override
     protected void onParentChanged(
             ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        ActivityDisplay display = getParent();
+        if (oldParent != null) {
+            mPrevDisplayId = ((ActivityDisplay) oldParent).mDisplayId;
+        }
+
+        final ActivityDisplay display = getParent();
         if (display != null) {
             // Rotations are relative to the display. This means if there are 2 displays rotated
             // differently (eg. 2 monitors with one landscape and one portrait), moving a stack
@@ -292,18 +296,6 @@
         RESTARTING_PROCESS
     }
 
-    @VisibleForTesting
-    /* The various modes for the method {@link #removeTask}. */
-    // Task is being completely removed from all stacks in the system.
-    protected static final int REMOVE_TASK_MODE_DESTROYING = 0;
-    // Task is being removed from this stack so we can add it to another stack. In the case we are
-    // moving we don't want to perform some operations on the task like removing it from window
-    // manager or recents.
-    static final int REMOVE_TASK_MODE_MOVING = 1;
-    // Similar to {@link #REMOVE_TASK_MODE_MOVING} and the task will be added to the top of its new
-    // stack and the new stack will be on top of all stacks.
-    static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
-
     final ActivityTaskManagerService mService;
     final WindowManagerService mWindowManager;
 
@@ -381,6 +373,8 @@
     final int mStackId;
     /** The attached Display's unique identifier, or -1 if detached */
     int mDisplayId;
+    // Id of the previous display the stack was on.
+    int mPrevDisplayId = INVALID_DISPLAY;
 
     /** Stores the override windowing-mode from before a transient mode change (eg. split) */
     private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -962,7 +956,7 @@
     void positionChildWindowContainerAtTop(TaskRecord child) {
         if (mTaskStack != null) {
             // TODO: Remove after unification. This cannot be false after that.
-            mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */);
+            mTaskStack.positionChildAtTop(child, true /* includingParents */);
         }
     }
 
@@ -974,7 +968,7 @@
                 child.getStack(), true /* ignoreCurrent */);
         if (mTaskStack != null) {
             // TODO: Remove after unification. This cannot be false after that.
-            mTaskStack.positionChildAtBottom(child.getTask(),
+            mTaskStack.positionChildAtBottom(child,
                     nextFocusableStack == null /* includingParents */);
         }
     }
@@ -1168,7 +1162,7 @@
         }
         final TaskRecord task = r.getTaskRecord();
         final ActivityStack stack = r.getActivityStack();
-        if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+        if (stack != null && task.mChildren.contains(r) && mTaskHistory.contains(task)) {
             if (stack != this) Slog.w(TAG,
                     "Illegal state! task does not point to stack it is in.");
             return r;
@@ -1183,7 +1177,8 @@
     /** Checks if there are tasks with specific UID in the stack. */
     boolean isUidPresent(int uid) {
         for (TaskRecord task : mTaskHistory) {
-            for (ActivityRecord r : task.mActivities) {
+            for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
+                final ActivityRecord r = task.getChildAt(i);
                 if (r.getUid() == uid) {
                     return true;
                 }
@@ -1195,7 +1190,8 @@
     /** Get all UIDs that are present in the stack. */
     void getPresentUIDs(IntArray presentUIDs) {
         for (TaskRecord task : mTaskHistory) {
-            for (ActivityRecord r : task.mActivities) {
+            for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
+                final ActivityRecord r = task.getChildAt(i);
                 presentUIDs.add(r.getUid());
             }
         }
@@ -1207,12 +1203,6 @@
         return display != null && display.isSingleTaskInstance();
     }
 
-    private void removeActivitiesFromLRUList(TaskRecord task) {
-        for (ActivityRecord r : task.mActivities) {
-            mLRUActivities.remove(r);
-        }
-    }
-
     /** @return {@code true} if LRU list contained the specified activity. */
     final boolean removeActivityFromLRUList(ActivityRecord activity) {
         return mLRUActivities.remove(activity);
@@ -3015,19 +3005,19 @@
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
         if (mTaskStack != null) {
-            // TODO: this could not be false after unification.
-            mTaskStack.positionChildAt(task.getTask(), position);
+            // TODO: this can not be false after unification Stack.
+            mTaskStack.positionChildAt(task, position);
         }
-        updateTaskMovement(task, true);
+        task.updateTaskMovement(true);
     }
 
-    private void insertTaskAtTop(TaskRecord task, ActivityRecord starting) {
-        // TODO: Better place to put all the code below...may be addTask...
+    void insertTaskAtTop(TaskRecord task, ActivityRecord starting) {
+        // TODO: Better place to put all the code below...may be addChild...
         mTaskHistory.remove(task);
         // Now put task at top.
         final int position = getAdjustedPositionForTask(task, mTaskHistory.size(), starting);
         mTaskHistory.add(position, task);
-        updateTaskMovement(task, true);
+        task.updateTaskMovement(true);
         positionChildWindowContainerAtTop(task);
     }
 
@@ -3035,7 +3025,7 @@
         mTaskHistory.remove(task);
         final int position = getAdjustedPositionForTask(task, 0, null);
         mTaskHistory.add(position, task);
-        updateTaskMovement(task, true);
+        task.updateTaskMovement(true);
         positionChildWindowContainerAtBottom(task);
     }
 
@@ -3069,7 +3059,7 @@
                     if (!startIt) {
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                 + task, new RuntimeException("here").fillInStackTrace());
-                        r.setTask(rTask);
+                        rTask.positionChildAtTop(r);
                         ActivityOptions.abort(options);
                         return;
                     }
@@ -3096,7 +3086,7 @@
         // Slot the activity into the history stack and proceed
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
                 new RuntimeException("here").fillInStackTrace());
-        r.setTask(task);
+        task.positionChildAtTop(r);
 
         // The transition animation and starting window are not needed if {@code allowMoveToFront}
         // is false, because the activity won't be visible.
@@ -3271,7 +3261,7 @@
                 // with the same affinity is unlikely to be in the same stack.
                 final TaskRecord targetTask;
                 final ActivityRecord bottom =
-                        !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
+                        !mTaskHistory.isEmpty() && mTaskHistory.get(0).hasChild() ?
                                 mTaskHistory.get(0).getChildAt(0) : null;
                 if (bottom != null && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) {
                     // If the activity currently at the bottom has the
@@ -3482,7 +3472,7 @@
                     // instance of the same activity?  Then we drop the instance
                     // below so it remains singleTop.
                     if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
-                        final ArrayList<ActivityRecord> taskActivities = task.mActivities;
+                        final ArrayList<ActivityRecord> taskActivities = task.mChildren;
                         final int targetNdx = taskActivities.indexOf(target);
                         if (targetNdx > 0) {
                             final ActivityRecord p = taskActivities.get(targetNdx - 1);
@@ -3636,7 +3626,7 @@
         finishedTask = r.getTaskRecord();
         int taskNdx = mTaskHistory.indexOf(finishedTask);
         final TaskRecord task = finishedTask;
-        int activityNdx = task.mActivities.indexOf(r);
+        int activityNdx = task.mChildren.indexOf(r);
         getDisplay().mDisplayContent.prepareAppTransition(
                 TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
         r.finishIfPossible(reason, false /* oomAdj */);
@@ -3773,7 +3763,7 @@
     final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
             Intent resultData) {
         final TaskRecord task = srec.getTaskRecord();
-        final ArrayList<ActivityRecord> activities = task.mActivities;
+        final ArrayList<ActivityRecord> activities = task.mChildren;
         final int start = activities.indexOf(srec);
         if (!mTaskHistory.contains(task) || (start < 0)) {
             return false;
@@ -3867,8 +3857,16 @@
      * an activity moves away from the stack.
      */
     void onActivityRemovedFromStack(ActivityRecord r) {
+        removeActivityFromLRUList(r);
         removeTimeoutsForActivity(r);
 
+        // TODO(stack-unify): null check will no longer be needed.
+        if (mTaskStack != null) {
+            mTaskStack.mExitingActivities.remove(r);
+        }
+        // TODO(stack-unify): Remove if no bugs showed up...
+        //r.mIsExiting = false;
+
         if (mResumedActivity != null && mResumedActivity == r) {
             setResumedActivity(null, "onActivityRemovedFromStack");
         }
@@ -4061,7 +4059,7 @@
         if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                 "Removing app " + app + " from history with " + i + " entries");
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren;
             mTmpActivities.clear();
             mTmpActivities.addAll(activities);
 
@@ -4150,19 +4148,6 @@
         getDisplay().mDisplayContent.prepareAppTransition(transit, false);
     }
 
-    private void updateTaskMovement(TaskRecord task, boolean toFront) {
-        if (task.isPersistable) {
-            task.mLastTimeMoved = System.currentTimeMillis();
-            // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
-            // recently will be most negative, tasks sent to the bottom before that will be less
-            // negative. Similarly for recent tasks moved to the top which will be most positive.
-            if (!toFront) {
-                task.mLastTimeMoved *= -1;
-            }
-        }
-        mRootActivityContainer.invalidateTaskLayers();
-    }
-
     final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
             AppTimeTracker timeTracker, String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
@@ -4295,7 +4280,7 @@
 
         mTaskHistory.remove(tr);
         mTaskHistory.add(0, tr);
-        updateTaskMovement(tr, false);
+        tr.updateTaskMovement(false);
 
         getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
         moveToBack("moveTaskToBackLocked", tr);
@@ -4334,7 +4319,7 @@
 
         for (int taskIndex = mTaskHistory.indexOf(startTask); taskIndex >= 0; --taskIndex) {
             final TaskRecord task = mTaskHistory.get(taskIndex);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final ArrayList<ActivityRecord> activities = task.mChildren;
             int activityIndex = (start.getTaskRecord() == task)
                     ? activities.indexOf(start) : activities.size() - 1;
             for (; activityIndex >= 0; --activityIndex) {
@@ -4374,10 +4359,10 @@
                 final TaskRecord task = mTaskHistory.get(i);
                 if (task.isResizeable()) {
                     if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) {
-                        task.setDisplayedBounds(taskBounds);
+                        task.setOverrideDisplayedBounds(taskBounds);
                         task.setBounds(tempTaskInsetBounds);
                     } else {
-                        task.setDisplayedBounds(null);
+                        task.setOverrideDisplayedBounds(null);
                         task.setBounds(taskBounds);
                     }
                 }
@@ -4429,9 +4414,9 @@
         for (int i = mTaskHistory.size() - 1; i >= 0; i--) {
             final TaskRecord task = mTaskHistory.get(i);
             if (bounds == null || bounds.isEmpty()) {
-                task.setDisplayedBounds(null);
+                task.setOverrideDisplayedBounds(null);
             } else if (task.isResizeable()) {
-                task.setDisplayedBounds(bounds);
+                task.setOverrideDisplayedBounds(bounds);
             }
         }
     }
@@ -4476,7 +4461,7 @@
         TaskRecord lastTask = null;
         ComponentName homeActivity = null;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren;
             mTmpActivities.clear();
             mTmpActivities.addAll(activities);
 
@@ -4674,7 +4659,7 @@
             pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
             pw.println(prefix + "* " + task);
             task.dump(pw, prefix + "  ");
-            dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities,
+            dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mChildren,
                     prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task);
         }
         return true;
@@ -4685,15 +4670,15 @@
 
         if ("all".equals(name)) {
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-                activities.addAll(mTaskHistory.get(taskNdx).mActivities);
+                activities.addAll(mTaskHistory.get(taskNdx).mChildren);
             }
         } else if ("top".equals(name)) {
             final int top = mTaskHistory.size() - 1;
             if (top >= 0) {
-                final ArrayList<ActivityRecord> list = mTaskHistory.get(top).mActivities;
-                int listTop = list.size() - 1;
+                final TaskRecord task = mTaskHistory.get(top);
+                int listTop = task.getChildCount() - 1;
                 if (listTop >= 0) {
-                    activities.add(list.get(listTop));
+                    activities.add(task.getChildAt(listTop));
                 }
             }
         } else {
@@ -4701,7 +4686,9 @@
             matcher.build(name);
 
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-                for (ActivityRecord r1 : mTaskHistory.get(taskNdx).mActivities) {
+                final TaskRecord task = mTaskHistory.get(taskNdx);
+                for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+                    final ActivityRecord r1 = task.getChildAt(activityNdx);
                     if (matcher.match(r1, r1.intent.getComponent())) {
                         activities.add(r1);
                     }
@@ -4733,57 +4720,50 @@
         return starting;
     }
 
+    // TODO(stack-unify): Merge into removeChild method below.
+    void onChildRemoved(TaskRecord child, DisplayContent dc) {
+        mTaskHistory.remove(child);
+        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId);
+
+        ActivityDisplay display = getDisplay();
+        if (display == null && dc != null) {
+            display = dc.mActivityDisplay;
+        }
+
+        if (display.isSingleTaskInstance()) {
+            mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
+        }
+
+        display.mDisplayContent.setLayoutNeeded();
+
+        if (mTaskHistory.isEmpty()) {
+            // Stack is now empty...
+            remove();
+        }
+    }
+
     /**
      * Removes the input task from this stack.
      *
      * @param task to remove.
      * @param reason for removal.
-     * @param mode task removal mode. Either {@link #REMOVE_TASK_MODE_DESTROYING},
-     *             {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
      */
-    void removeTask(TaskRecord task, String reason, int mode) {
-        if (!mTaskHistory.remove(task)) {
-            // Not really in this stack anymore...
-            return;
-        }
-
-        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId());
-
-        removeActivitiesFromLRUList(task);
-        updateTaskMovement(task, true);
-
-        if (mode == REMOVE_TASK_MODE_DESTROYING) {
-            task.cleanUpResourcesForDestroy();
-        }
-
+    void removeChild(TaskRecord task, String reason) {
         final ActivityDisplay display = getDisplay();
-        if (mTaskHistory.isEmpty()) {
-            if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
+        final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this);
+        mTaskStack.removeChild(task);
+        moveHomeStackToFrontIfNeeded(topFocused, display, reason);
+    }
+
+    void moveHomeStackToFrontIfNeeded(
+            boolean wasTopFocusedStack, ActivityDisplay display, String reason) {
+        if (mTaskHistory.isEmpty() && wasTopFocusedStack) {
             // We only need to adjust focused stack if this stack is in focus and we are not in the
             // process of moving the task to the top of the stack that will be focused.
-            if (mode != REMOVE_TASK_MODE_MOVING_TO_TOP
-                    && mRootActivityContainer.isTopDisplayFocusedStack(this)) {
-                String myReason = reason + " leftTaskHistoryEmpty";
-                if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) {
-                    display.moveHomeStackToFront(myReason);
-                }
+            String myReason = reason + " leftTaskHistoryEmpty";
+            if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) {
+                display.moveHomeStackToFront(myReason);
             }
-            if (isAttached()) {
-                display.positionChildAtBottom(this);
-            }
-            if (!isActivityTypeHome() || !isAttached()) {
-                remove();
-            }
-        }
-
-        task.setStack(null);
-
-        // Notify if a task from the pinned stack is being removed (or moved depending on the mode)
-        if (inPinnedWindowingMode()) {
-            mService.getTaskChangeNotificationController().notifyActivityUnpinned();
-        }
-        if (display != null && display.isSingleTaskInstance()) {
-            mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
         }
     }
 
@@ -4799,9 +4779,9 @@
             boolean toTop, ActivityRecord activity, ActivityRecord source,
             ActivityOptions options) {
         final TaskRecord task = TaskRecord.create(
-                mService, taskId, info, intent, voiceSession, voiceInteractor);
+                mService, taskId, info, intent, voiceSession, voiceInteractor, this);
         // add the task to stack first, mTaskPositioner might need the stack association
-        addTask(task, toTop, "createTaskRecord");
+        addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
         final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
                 .isKeyguardOrAodShowing(displayId);
@@ -4810,7 +4790,6 @@
                 && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
             task.setBounds(getRequestedOverrideBounds());
         }
-        task.createTask(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         return task;
     }
 
@@ -4818,34 +4797,31 @@
         return new ArrayList<>(mTaskHistory);
     }
 
-    void addTask(final TaskRecord task, final boolean toTop, String reason) {
-        addTask(task, toTop ? MAX_VALUE : 0, true /* schedulePictureInPictureModeChange */, reason);
-        if (toTop) {
-            // TODO: figure-out a way to remove this call.
-            positionChildWindowContainerAtTop(task);
-        }
+    // TODO(stack-unify): Merge with addChild below.
+    void onChildAdded(TaskRecord task, int position) {
+        final boolean toTop = position >= mTaskHistory.size();
+        mTaskHistory.add(position, task);
+
+        // TODO: Feels like this should go in TaskRecord#onParentChanged
+        task.updateTaskMovement(toTop);
     }
 
-    // TODO: This shouldn't allow automatic reparenting. Remove the call to preAddTask and deal
-    // with the fall-out...
-    void addTask(final TaskRecord task, int position, boolean schedulePictureInPictureModeChange,
-            String reason) {
-        // TODO: Is this remove really needed? Need to look into the call path for the other addTask
-        mTaskHistory.remove(task);
+    void addChild(final TaskRecord task, final boolean toTop, boolean showForAllUsers) {
         if (isSingleTaskInstance() && !mTaskHistory.isEmpty()) {
             throw new IllegalStateException("Can only have one child on stack=" + this);
         }
 
-        position = getAdjustedPositionForTask(task, position, null /* starting */);
-        final boolean toTop = position >= mTaskHistory.size();
-        final ActivityStack prevStack = preAddTask(task, reason, toTop);
+        final int position =
+                getAdjustedPositionForTask(task, toTop ? MAX_VALUE : 0, null /* starting */);
 
-        mTaskHistory.add(position, task);
-        task.setStack(this);
+        // We only want to move the parents to the parents if we are creating this task at the
+        // top of its stack.
+        mTaskStack.addChild(task, position, showForAllUsers, toTop /*moveParents*/);
 
-        updateTaskMovement(task, toTop);
-
-        postAddTask(task, prevStack, schedulePictureInPictureModeChange);
+        if (toTop) {
+            // TODO: figure-out a way to remove this call.
+            positionChildWindowContainerAtTop(task);
+        }
     }
 
     void positionChildAt(TaskRecord task, int index) {
@@ -4860,8 +4836,14 @@
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
         insertTaskAtPosition(task, index);
-        task.setStack(this);
-        postAddTask(task, null /* prevStack */, true /* schedulePictureInPictureModeChange */);
+
+        // TODO: Investigate if this random code is really needed.
+        if (task.voiceSession != null) {
+            try {
+                task.voiceSession.taskStarted(task.intent, task.mTaskId);
+            } catch (RemoteException e) {
+            }
+        }
 
         if (wasResumed) {
             if (mResumedActivity != null) {
@@ -4878,32 +4860,6 @@
         mRootActivityContainer.resumeFocusedStacksTopActivities();
     }
 
-    private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
-        final ActivityStack prevStack = task.getStack();
-        if (prevStack != null && prevStack != this) {
-            prevStack.removeTask(task, reason,
-                    toTop ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
-        }
-        return prevStack;
-    }
-
-    /**
-     * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
-     *            change. Callers may set this to false if they are explicitly scheduling PiP mode
-     *            changes themselves, like during the PiP animation
-     */
-    private void postAddTask(TaskRecord task, ActivityStack prevStack,
-            boolean schedulePictureInPictureModeChange) {
-        if (schedulePictureInPictureModeChange && prevStack != null) {
-            mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, prevStack);
-        } else if (task.voiceSession != null) {
-            try {
-                task.voiceSession.taskStarted(task.intent, task.mTaskId);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
     public void setAlwaysOnTop(boolean alwaysOnTop) {
         if (isAlwaysOnTop() == alwaysOnTop) {
             return;
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index dc3d263..f8a7397 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -52,7 +52,6 @@
 
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
@@ -83,6 +82,7 @@
 import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import android.Manifest;
 import android.app.Activity;
@@ -1420,7 +1420,7 @@
                 // WM resizeTask must be done after the task is moved to the correct stack,
                 // because Task's setBounds() also updates dim layer's bounds, but that has
                 // dependency on the stack.
-                task.resizeWindowContainer();
+                task.resize(false /* relayout */, false /* forced */);
             }
         }
 
@@ -1885,26 +1885,22 @@
         final ActivityStack stack =
                 mRootActivityContainer.getLaunchStack(null, aOptions, task, onTop);
         final ActivityStack currentStack = task.getStack();
-        if (currentStack != null) {
-            // Task has already been restored once. See if we need to do anything more
-            if (currentStack == stack) {
-                // Nothing else to do since it is already restored in the right stack.
-                return true;
-            }
-            // Remove current stack association, so we can re-associate the task with the
-            // right stack below.
-            currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
+
+        if (currentStack == stack) {
+            // Nothing else to do since it is already restored in the right stack.
+            return true;
         }
 
-        stack.addTask(task, onTop, "restoreRecentTask");
-        // TODO: move call for creation here and other place into Stack.addTask()
-        task.createTask(onTop, true /* showForAllUsers */);
+        if (currentStack != null) {
+            // Task has already been restored once. Just re-parent it to the new stack.
+            task.reparent(stack.mTaskStack,
+                    POSITION_TOP, true /*moveParents*/, "restoreRecentTaskLocked");
+            return true;
+        }
+
+        stack.addChild(task, onTop, true /* showForAllUsers */);
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
                 "Added restored task=" + task + " to stack=" + stack);
-        for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-            final ActivityRecord r = task.getChildAt(activityNdx);
-            r.setTask(task);
-        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d1bb255..6edcb02 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -50,6 +50,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -1842,7 +1843,7 @@
             // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task
             // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded}
             if (targetTaskTop.getTaskRecord() == null) {
-                targetTaskTop.setTask(targetTask);
+                targetTask.addChild(targetTaskTop);
             }
 
             if (top != null) {
@@ -1862,8 +1863,8 @@
                     // Go ahead and reset it.
                     mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
                             mLaunchFlags, mOptions);
-                    mTargetStack.addTask(targetTask,
-                            !mLaunchTaskBehind /* toTop */, "complyActivityFlags");
+                    mTargetStack.addChild(targetTask, !mLaunchTaskBehind /* toTop */,
+                            (mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
                 }
             }
         } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) == 0 && !mAddingToTask
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 222f26e..da7af5f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -85,7 +85,6 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -1996,7 +1995,7 @@
                     return false;
                 }
                 final TaskRecord task = r.getTaskRecord();
-                int index = task.mActivities.lastIndexOf(r);
+                int index = task.mChildren.lastIndexOf(r);
                 if (index > 0) {
                     ActivityRecord under = task.getChildAt(index - 1);
                     under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
@@ -2221,18 +2220,10 @@
                     Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
                     return rect;
                 }
-                if (task.getStack() != null) {
-                    // Return the bounds from window manager since it will be adjusted for various
-                    // things like the presense of a docked stack for tasks that aren't resizeable.
-                    task.getWindowContainerBounds(rect);
-                } else {
-                    // Task isn't in window manager yet since it isn't associated with a stack.
-                    // Return the persist value from activity manager
-                    if (!task.matchParentBounds()) {
-                        rect.set(task.getBounds());
-                    } else if (task.mLastNonFullscreenBounds != null) {
-                        rect.set(task.mLastNonFullscreenBounds);
-                    }
+                if (task.getParent() != null) {
+                    rect.set(task.getBounds());
+                } else if (task.mLastNonFullscreenBounds != null) {
+                    rect.set(task.mLastNonFullscreenBounds);
                 }
             }
         } finally {
@@ -2249,7 +2240,7 @@
             final TaskRecord tr = mRootActivityContainer.anyTaskForId(id,
                     MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
             if (tr != null) {
-                return tr.mTaskDescription;
+                return tr.getTaskDescription();
             }
         }
         return null;
@@ -3168,10 +3159,10 @@
                         null /* voiceSession */, null /* voiceInteractor */, !ON_TOP);
                 if (!mRecentTasks.addToBottom(task)) {
                     // The app has too many tasks already and we can't add any more
-                    stack.removeTask(task, "addAppTask", REMOVE_TASK_MODE_DESTROYING);
+                    stack.removeChild(task, "addAppTask");
                     return INVALID_TASK_ID;
                 }
-                task.mTaskDescription.copyFrom(description);
+                task.getTaskDescription().copyFrom(description);
 
                 // TODO: Send the thumbnail to WM to store it.
 
@@ -4489,7 +4480,7 @@
                     Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
                     return;
                 }
-                task.cancelWindowTransition();
+                task.cancelTaskWindowTransition();
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 8b4f7cc..30f3bc5 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -134,9 +134,9 @@
         onConfigurationChanged(newParentConfig, true /*forwardToChildren*/);
     }
 
-    // TODO: Consolidate with onConfigurationChanged() method above once unification is done. This
-    // is only currently need during the process of unification where we don't want configuration
-    // forwarded to a child from both parents.
+    // TODO(root-unify): Consolidate with onConfigurationChanged() method above once unification is
+    //  done. This is only currently need during the process of unification where we don't want
+    //  configuration forwarded to a child from both parents.
     public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
         mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
         resolveOverrideConfiguration(newParentConfig);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 89568eb..d1d468b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2409,7 +2409,19 @@
     /** Returns true if a removal action is still being deferred. */
     @Override
     boolean checkCompleteDeferredRemoval() {
-        final boolean stillDeferringRemoval = super.checkCompleteDeferredRemoval();
+        boolean stillDeferringRemoval = false;
+
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final DisplayChildWindowContainer child = getChildAt(i);
+            stillDeferringRemoval |= child.checkCompleteDeferredRemoval();
+            if (getChildCount() == 0) {
+                // If this display is pending to be removed because it contains an activity with
+                // {@link ActivityRecord#mIsExiting} is true, this display may be removed when
+                // completing the removal of the last activity from
+                // {@link ActivityRecord#checkCompleteDeferredRemoval}.
+                return false;
+            }
+        }
 
         if (!stillDeferringRemoval && mDeferredRemoval) {
             removeImmediately();
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 2dae126..01cbc5d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -211,9 +211,9 @@
                 // If there are multiple tasks in the target stack (ie. the home stack, with 3p
                 // and default launchers coexisting), then move the task to the top as a part of
                 // moving the stack to the front
-                if (targetStack.topTask() != targetActivity.getTaskRecord()) {
-                    targetStack.addTask(targetActivity.getTaskRecord(), true /* toTop */,
-                            "startRecentsActivity");
+                final TaskRecord task = targetActivity.getTaskRecord();
+                if (targetStack.topTask() != task) {
+                    targetStack.insertTaskAtTop(task, targetActivity);
                 }
             } else {
                 // No recents activity, create the new recents activity bottom most
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 51a3e720..dc78922 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1265,8 +1265,7 @@
                     : task.realActivity != null ? task.realActivity.flattenToString()
                     : task.getTopActivity() != null ? task.getTopActivity().packageName
                     : "unknown";
-            taskBounds[i] = new Rect();
-            task.getWindowContainerBounds(taskBounds[i]);
+            taskBounds[i] = mService.getTaskBounds(task.mTaskId);
             taskUserIds[i] = task.mUserId;
         }
         info.taskIds = taskIds;
@@ -1876,7 +1875,12 @@
     ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus,
             boolean ignoreCurrent) {
         // First look for next focusable stack on the same display
-        final ActivityDisplay preferredDisplay = currentFocus.getDisplay();
+        ActivityDisplay preferredDisplay = currentFocus.getDisplay();
+        if (preferredDisplay == null) {
+            // Stack is currently detached because it is being removed. Use the previous display it
+            // was on.
+            preferredDisplay = getActivityDisplay(currentFocus.mPrevDisplayId);
+        }
         final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack(
                 currentFocus, ignoreCurrent);
         if (preferredFocusableStack != null) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f5d3aff..149bcfb 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -206,7 +206,7 @@
     }
 
     @Override
-    void onChildPositionChanged() {
+    void onChildPositionChanged(WindowContainer child) {
         mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                 !mWmService.mPerDisplayFocusEnabled /* updateInputWindows */);
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 634990b..dce15bc 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -24,6 +25,7 @@
 import static android.content.res.Configuration.EMPTY;
 import static android.view.SurfaceControl.METADATA_TASK_ID;
 
+import static com.android.server.EventLogTags.WM_TASK_CREATED;
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
@@ -63,17 +65,21 @@
 class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener{
     static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
 
+    final ActivityTaskManagerService mAtmService;
+
     // TODO: Track parent marks like this in WindowContainer.
     TaskStack mStack;
     /* Unique identifier for this task. */
     final int mTaskId;
     /* User for which this task was created. */
-    final int mUserId;
+    // TODO: Make final
+    int mUserId;
 
     final Rect mPreparedFrozenBounds = new Rect();
     final Configuration mPreparedFrozenMergedConfig = new Configuration();
 
     // If non-empty, bounds used to display the task during animations/interactions.
+    // TODO(b/119687367): This member is temporary.
     private final Rect mOverrideDisplayedBounds = new Rect();
 
     /** ID of the display which rotation {@link #mRotation} has. */
@@ -90,11 +96,12 @@
     private Rect mTmpRect2 = new Rect();
 
     // Resize mode of the task. See {@link ActivityInfo#resizeMode}
-    private int mResizeMode;
+    // Based on the {@link ActivityInfo#resizeMode} of the root activity.
+    int mResizeMode;
 
-    // Whether the task supports picture-in-picture.
-    // See {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE}
-    private boolean mSupportsPictureInPicture;
+    // Whether or not this task and its activities support PiP. Based on the
+    // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity.
+    boolean mSupportsPictureInPicture;
 
     // Whether the task is currently being drag-resized
     private boolean mDragResizing;
@@ -116,40 +123,23 @@
     /** @see #setCanAffectSystemUiFlags */
     private boolean mCanAffectSystemUiFlags = true;
 
-    // TODO: remove after unification
-    TaskRecord mTaskRecord;
-
-    // TODO: Remove after unification.
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
-        // Forward configuration changes in cases
-        // - children won't get it from TaskRecord
-        // - it's a pinned task
-        forwardToChildren &= (mTaskRecord == null) || inPinnedWindowingMode();
-        super.onConfigurationChanged(newParentConfig, forwardToChildren);
-    }
-
-    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode,
-            boolean supportsPictureInPicture, TaskDescription taskDescription,
-            TaskRecord taskRecord) {
-        super(service);
+    Task(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture,
+            TaskDescription taskDescription, ActivityTaskManagerService atm) {
+        super(atm.mWindowManager);
+        mAtmService = atm;
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mResizeMode = resizeMode;
         mSupportsPictureInPicture = supportsPictureInPicture;
-        mTaskRecord = taskRecord;
         mTaskDescription = taskDescription;
+        EventLog.writeEvent(WM_TASK_CREATED, mTaskId,
+                stack != null ? stack.mStackId : INVALID_STACK_ID);
 
         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
         setOrientation(SCREEN_ORIENTATION_UNSET);
-        if (mTaskRecord != null) {
-            // This can be null when we call createTaskInStack in WindowTestUtils. Remove this after
-            // unification.
-            mTaskRecord.registerConfigurationChangeListener(this);
-        } else {
-            setBounds(getResolvedOverrideBounds());
-        }
+        // TODO(task-merge): Is this really needed?
+        setBounds(getResolvedOverrideBounds());
     }
 
     @Override
@@ -157,37 +147,40 @@
         return mStack != null ? mStack.getDisplayContent() : null;
     }
 
-    private int getAdjustedAddPosition(int suggestedPosition) {
-        final int size = mChildren.size();
-        if (suggestedPosition >= size) {
-            return Math.min(size, suggestedPosition);
+    int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
+        int maxPosition = mChildren.size();
+        if (!r.mTaskOverlay) {
+            // We want to place all non-overlay activities below overlays.
+            while (maxPosition > 0) {
+                final ActivityRecord current = mChildren.get(maxPosition - 1);
+                if (current.mTaskOverlay && !current.removed) {
+                    --maxPosition;
+                    continue;
+                }
+                break;
+            }
+            if (maxPosition < 0) {
+                maxPosition = 0;
+            }
         }
 
-        for (int pos = 0; pos < size && pos < suggestedPosition; ++pos) {
+        if (suggestedPosition >= maxPosition) {
+            return Math.min(maxPosition, suggestedPosition);
+        }
+
+        for (int pos = 0; pos < maxPosition && pos < suggestedPosition; ++pos) {
             // TODO: Confirm that this is the behavior we want long term.
             if (mChildren.get(pos).removed) {
                 // suggestedPosition assumes removed tokens are actually gone.
                 ++suggestedPosition;
             }
         }
-        return Math.min(size, suggestedPosition);
-    }
-
-    @Override
-    void addChild(ActivityRecord child, int position) {
-        position = getAdjustedAddPosition(position);
-        super.addChild(child, position);
-
-        // Inform the TaskRecord side of the child addition
-        // TODO(task-unify): Will be removed after task unification.
-        if (mTaskRecord != null) {
-            mTaskRecord.onChildAdded(child, position);
-        }
+        return Math.min(maxPosition, suggestedPosition);
     }
 
     @Override
     void positionChildAt(int position, ActivityRecord child, boolean includingParents) {
-        position = getAdjustedAddPosition(position);
+        position = getAdjustedAddPosition(child, position);
         super.positionChildAt(position, child, includingParents);
     }
 
@@ -222,47 +215,34 @@
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
-        if (mTaskRecord != null) {
-            mTaskRecord.unregisterConfigurationChangeListener(this);
-        }
-
         super.removeImmediately();
     }
 
-    void reparent(TaskStack stack, int position, boolean moveParents) {
-        if (stack == mStack) {
-            throw new IllegalArgumentException(
-                    "task=" + this + " already child of stack=" + mStack);
-        }
-        if (stack == null) {
-            throw new IllegalArgumentException("reparent: could not find stack.");
-        }
+    // TODO: Consolidate this with TaskRecord.reparent()
+    void reparent(TaskStack stack, int position, boolean moveParents, String reason) {
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
-        final DisplayContent prevDisplayContent = getDisplayContent();
 
-        // If we are moving from the fullscreen stack to the pinned stack
-        // then we want to preserve our insets so that there will not
-        // be a jump in the area covered by system decorations. We rely
-        // on the pinned animation to later unset this value.
-        if (stack.inPinnedWindowingMode()) {
-            mPreserveNonFloatingState = true;
-        } else {
-            mPreserveNonFloatingState = false;
+        final ActivityStack prevStack = mStack.mActivityStack;
+        final boolean wasTopFocusedStack =
+                mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
+        final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
+
+        reparent(stack, position);
+
+        if (!moveParents) {
+            // Only move home stack forward if we are not going to move the new parent forward.
+            prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
         }
 
-        getParent().removeChild(this);
-        stack.addTask(this, position, showForAllUsers(), moveParents);
+        mStack = stack;
+        stack.positionChildAt(position, this, moveParents);
 
-        // Relayout display(s).
-        final DisplayContent displayContent = stack.getDisplayContent();
-        displayContent.setLayoutNeeded();
-        if (prevDisplayContent != displayContent) {
-            onDisplayChanged(displayContent);
-            prevDisplayContent.setLayoutNeeded();
-        }
-        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+        // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
+        // our insets so that there will not be a jump in the area covered by system decorations.
+        // We rely on the pinned animation to later unset this value.
+        mPreserveNonFloatingState = stack.inPinnedWindowingMode();
     }
 
     /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */
@@ -270,46 +250,6 @@
         mStack.positionChildAt(position, this, false /* includingParents */);
     }
 
-    @Override
-    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        super.onParentChanged(newParent, oldParent);
-
-        // Update task bounds if needed.
-        adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
-
-        if (getWindowConfiguration().windowsAreScaleable()) {
-            // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
-            // while a resize is pending.
-            forceWindowsScaleable(true /* force */);
-        } else {
-            forceWindowsScaleable(false /* force */);
-        }
-    }
-
-    @Override
-    void removeChild(ActivityRecord child) {
-        if (!mChildren.contains(child)) {
-            Slog.e(TAG, "removeChild: token=" + this + " not found.");
-            return;
-        }
-
-        super.removeChild(child);
-
-        // Inform the TaskRecord side of the child removal
-        // TODO(task-unify): Will be removed after task unification.
-        if (mTaskRecord != null) {
-            mTaskRecord.onChildRemoved(child);
-        }
-
-        // TODO(task-unify): Need to make this account for what we are doing in
-        // ActivityRecord.removeFromHistory so that the task isn't removed in some situations when
-        // we unify task level.
-        if (mChildren.isEmpty()) {
-            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeActivity: last activity");
-            removeIfPossible();
-        }
-    }
-
     void setSendingToBottom(boolean toBottom) {
         for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) {
             mChildren.get(appTokenNdx).sendingToBottom = toBottom;
@@ -331,7 +271,7 @@
     @Override
     public int setBounds(Rect bounds) {
         int rotation = Surface.ROTATION_0;
-        final DisplayContent displayContent = mStack.getDisplayContent();
+        final DisplayContent displayContent = mStack != null ? mStack.getDisplayContent() : null;
         if (displayContent != null) {
             rotation = displayContent.getDisplayInfo().rotation;
         } else if (bounds == null) {
@@ -355,9 +295,8 @@
 
         // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
         // it if possible.
-        // TODO: Move to TaskRecord after unification is done.
-        if (mTaskRecord != null && mTaskRecord.getParent() != null) {
-            mTaskRecord.onConfigurationChanged(mTaskRecord.getParent().getConfiguration());
+        if (getParent() != null) {
+            onConfigurationChanged(getParent().getConfiguration());
             return true;
         }
         return false;
@@ -379,8 +318,9 @@
     }
 
     /**
-     * Sets bounds that override where the task is displayed. Used during transient operations
-     * like animation / interaction.
+     * Displayed bounds are used to set where the task is drawn at any given time. This is
+     * separate from its actual bounds so that the app doesn't see any meaningful configuration
+     * changes during transitionary periods.
      */
     void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) {
         if (overrideDisplayedBounds != null) {
@@ -399,13 +339,13 @@
         return mOverrideDisplayedBounds;
     }
 
-    void setResizeable(int resizeMode) {
-        mResizeMode = resizeMode;
+    boolean isResizeable(boolean checkSupportsPip) {
+        return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
+                || (checkSupportsPip && mSupportsPictureInPicture));
     }
 
     boolean isResizeable() {
-        return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture
-                || mWmService.mAtmService.mForceResizableActivities;
+        return isResizeable(true /* checkSupportsPip */);
     }
 
     /**
@@ -462,6 +402,10 @@
         }
     }
 
+    /**
+     * Gets the current overridden displayed bounds. These will be empty if the task is not
+     * currently overriding where it is displayed.
+     */
     @Override
     public Rect getDisplayedBounds() {
         if (mOverrideDisplayedBounds.isEmpty()) {
@@ -577,7 +521,7 @@
         setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
     }
 
-    private void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
+    void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
         }
@@ -618,9 +562,7 @@
 
         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
-            if (mTaskRecord != null) {
-                mTaskRecord.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
-            }
+            mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
         }
     }
 
@@ -758,7 +700,8 @@
     }
 
     void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
-        mTaskRecord.onSnapshotChanged(snapshot);
+        mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
+                mTaskId, snapshot);
     }
 
     TaskDescription getTaskDescription() {
@@ -794,11 +737,6 @@
         mDimmer.dontAnimateExit();
     }
 
-    @Override
-    public String toString() {
-        return "{taskId=" + mTaskId + " appTokens=" + mChildren + "}";
-    }
-
     String getName() {
         return toShortString();
     }
@@ -825,9 +763,8 @@
         }
     }
 
-    @CallSuper
-    @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged.
+    void writeToProtoInnerTaskOnly(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
             return;
@@ -843,8 +780,10 @@
         proto.write(FILLS_PARENT, matchParentBounds());
         getBounds().writeToProto(proto, BOUNDS);
         mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
-        proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
-        proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
+        if (mSurfaceControl != null) {
+            proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
+            proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
+        }
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 6920d9d..672827f 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -52,11 +52,10 @@
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.server.EventLogTags.WM_TASK_CREATED;
+import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.am.TaskRecordProto.ACTIVITIES;
 import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
 import static com.android.server.am.TaskRecordProto.BOUNDS;
-import static com.android.server.am.TaskRecordProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.TaskRecordProto.FULLSCREEN;
 import static com.android.server.am.TaskRecordProto.ID;
 import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
@@ -66,11 +65,9 @@
 import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
 import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
 import static com.android.server.am.TaskRecordProto.STACK_ID;
+import static com.android.server.am.TaskRecordProto.TASK;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
@@ -85,10 +82,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import static java.lang.Integer.MAX_VALUE;
 
@@ -143,7 +136,7 @@
 import java.util.ArrayList;
 import java.util.Objects;
 
-class TaskRecord extends ConfigurationContainer {
+class TaskRecord extends Task {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -212,7 +205,6 @@
      */
     private static TaskRecordFactory sTaskRecordFactory;
 
-    final int mTaskId;      // Unique identifier for this task.
     String affinity;        // The affinity name for this task, or null; may change identity.
     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
     final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
@@ -238,17 +230,11 @@
     boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
 
     String stringName;      // caching of toString() result.
-    int mUserId;            // user for which this task was created
     boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
                                 // was changed.
 
     int numFullscreen;      // Number of fullscreen activities.
 
-    int mResizeMode;        // The resize mode of this task and its activities.
-                            // Based on the {@link ActivityInfo#resizeMode} of the root activity.
-    private boolean mSupportsPictureInPicture;  // Whether or not this task and its activities
-            // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag
-            // of the root activity.
     /** Can't be put in lockTask mode. */
     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
     /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
@@ -264,13 +250,6 @@
 
     int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
 
-    // This represents the last resolved activity values for this task
-    // NOTE: This value needs to be persisted with each task
-    TaskDescription mTaskDescription;
-
-    /** List of all activities in the task arranged in history order */
-    final ArrayList<ActivityRecord> mActivities;
-
     /** Current stack. Setter must always be used to update the value. */
     private ActivityStack mStack;
 
@@ -308,8 +287,6 @@
     int mCallingUid;
     String mCallingPackage;
 
-    final ActivityTaskManagerService mAtmService;
-
     private final Rect mTmpStableBounds = new Rect();
     private final Rect mTmpNonDecorBounds = new Rect();
     private final Rect mTmpBounds = new Rect();
@@ -328,17 +305,9 @@
     // This number will be assigned when we evaluate OOM scores for all visible tasks.
     int mLayerRank = -1;
 
-    // When non-empty, this represents the bounds this task will be drawn at. This gets set during
-    // transient operations such as split-divider dragging and animations.
-    // TODO(b/119687367): This member is temporary.
-    final Rect mDisplayedBounds = new Rect();
-
     /** Helper object used for updating override configuration. */
     private Configuration mTmpConfig = new Configuration();
 
-    // TODO: remove after unification
-    Task mTask;
-
     /** Used by fillTaskInfo */
     final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
 
@@ -346,21 +315,21 @@
      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
      * ActivityInfo, Intent, TaskDescription)} instead.
      */
-    TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info,
-            Intent _intent, IVoiceInteractionSession _voiceSession,
-            IVoiceInteractor _voiceInteractor, TaskDescription _taskDescription) {
+    TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
+            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+            TaskDescription _taskDescription, ActivityStack stack) {
         this(atmService, _taskId, _intent,  null /*_affinityIntent*/, null /*_affinity*/,
                 null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
                 false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
                 UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
-                null /*_lastDescription*/, new ArrayList<>(), System.currentTimeMillis(),
+                null /*_lastDescription*/, System.currentTimeMillis(),
                 true /*neverRelinquishIdentity*/,
                 _taskDescription != null ? _taskDescription : new TaskDescription(),
                 _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
                 info.applicationInfo.uid, info.packageName, info.resizeMode,
                 info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
                 false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
-                _voiceSession, _voiceInteractor);
+                _voiceSession, _voiceInteractor, stack);
     }
 
     /** Don't use constructor directly. This is only used by XML parser. */
@@ -368,15 +337,16 @@
             Intent _affinityIntent, String _affinity, String _rootAffinity,
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
             boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
-            int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
+            int _effectiveUid, String _lastDescription,
             long lastTimeMoved, boolean neverRelinquishIdentity,
             TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
             int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
             int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
             boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
-            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
-        mAtmService = atmService;
-        mTaskId = _taskId;
+            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+            ActivityStack stack) {
+        super(_taskId, stack != null ? stack.mTaskStack : null, _userId, resizeMode,
+                supportsPictureInPicture, _lastTaskDescription, atmService);
         mRemoteToken = new RemoteToken(this);
         affinityIntent = _affinityIntent;
         affinity = _affinity;
@@ -390,15 +360,12 @@
         isAvailable = true;
         autoRemoveRecents = _autoRemoveRecents;
         askedCompatMode = _askedCompatMode;
-        mUserId = _userId;
         mUserSetupComplete = userSetupComplete;
         effectiveUid = _effectiveUid;
         touchActiveTime();
         lastDescription = _lastDescription;
-        mActivities = activities;
         mLastTimeMoved = lastTimeMoved;
         mNeverRelinquishIdentity = neverRelinquishIdentity;
-        mTaskDescription = _lastTaskDescription;
         mAffiliatedTaskId = taskAffiliation;
         mAffiliatedTaskColor = taskAffiliationColor;
         mPrevAffiliateTaskId = prevTaskId;
@@ -406,7 +373,6 @@
         mCallingUid = callingUid;
         mCallingPackage = callingPackage;
         mResizeMode = resizeMode;
-        mSupportsPictureInPicture = supportsPictureInPicture;
         if (info != null) {
             setIntent(_intent, info);
             setMinDimensions(info);
@@ -418,39 +384,6 @@
         mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
     }
 
-    Task getTask() {
-        return mTask;
-    }
-
-    void createTask(boolean onTop, boolean showForAllUsers) {
-        if (mTask != null) {
-            throw new IllegalArgumentException("mTask=" + mTask
-                    + " already created for task=" + this);
-        }
-
-        final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
-        final TaskStack stack = getStack().getTaskStack();
-
-        if (stack == null) {
-            throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
-        }
-        EventLog.writeEvent(WM_TASK_CREATED, mTaskId, stack.mStackId);
-        mTask = new Task(mTaskId, stack, mUserId, mAtmService.mWindowManager, mResizeMode,
-                mSupportsPictureInPicture, mTaskDescription, this);
-        final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
-
-        if (!mDisplayedBounds.isEmpty()) {
-            mTask.setOverrideDisplayedBounds(mDisplayedBounds);
-        }
-        // We only want to move the parents to the parents if we are creating this task at the
-        // top of its stack.
-        stack.addTask(mTask, position, showForAllUsers, onTop /* moveParents */);
-    }
-
-    void setTask(Task task) {
-        mTask = task;
-    }
-
     void cleanUpResourcesForDestroy() {
         if (hasChild()) {
             return;
@@ -473,60 +406,33 @@
             mAtmService.mStackSupervisor.mRecentTasks.remove(this);
         }
 
-        removeWindowContainer();
+        removeIfPossible();
     }
 
     @VisibleForTesting
-    void removeWindowContainer() {
+    @Override
+    void removeIfPossible() {
         mAtmService.getLockTaskController().clearLockedTask(this);
-        if (mTask == null) {
-            if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId);
-            return;
-        }
-        mTask.removeIfPossible();
-        mTask = null;
-        if (!getWindowConfiguration().persistTaskBounds()) {
-            // Reset current bounds for task whose bounds shouldn't be persisted so it uses
-            // default configuration the next time it launches.
-            setBounds(null);
-        }
+        super.removeIfPossible();
         mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
     }
 
-    void onSnapshotChanged(TaskSnapshot snapshot) {
-        mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(mTaskId, snapshot);
-    }
-
     void setResizeMode(int resizeMode) {
         if (mResizeMode == resizeMode) {
             return;
         }
         mResizeMode = resizeMode;
-        mTask.setResizeable(resizeMode);
         mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
         mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
     }
 
-    void setTaskDockedResizing(boolean resizing) {
-        if (mTask == null) {
-            Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found.");
-            return;
-        }
-        mTask.setTaskDockedResizing(resizing);
-    }
-
-    // TODO: Consolidate this with the resize() method below.
-    public void requestResize(Rect bounds, int resizeMode) {
-        mAtmService.resizeTask(mTaskId, bounds, resizeMode);
-    }
-
     boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
         mAtmService.deferWindowLayout();
 
         try {
             final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
 
-            if (mTask == null) {
+            if (getParent() == null) {
                 // Task doesn't exist in window manager yet (e.g. was restored from recents).
                 // All we can do for now is update the bounds so it can be used when the task is
                 // added to window manager.
@@ -577,7 +483,7 @@
                     }
                 }
             }
-            mTask.resize(kept, forced);
+            resize(kept, forced);
 
             saveLaunchingStateIfNeeded();
 
@@ -588,19 +494,6 @@
         }
     }
 
-    // TODO: Investigate combining with the resize() method above.
-    void resizeWindowContainer() {
-        mTask.resize(false /* relayout */, false /* forced */);
-    }
-
-    void getWindowContainerBounds(Rect bounds) {
-        if (mTask != null) {
-            mTask.getBounds(bounds);
-        } else {
-            bounds.setEmpty();
-        }
-    }
-
     /**
      * Convenience method to reparent a task to the top or bottom position of the stack.
      */
@@ -708,32 +601,16 @@
             // Adjust the position for the new parent stack as needed.
             position = toStack.getAdjustedPositionForTask(this, position, null /* starting */);
 
-            // Must reparent first in window manager to avoid a situation where AM can delete the
-            // we are coming from in WM before we reparent because it became empty.
-            mTask.reparent(toStack.getTaskStack(), position,
-                    moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
-
             final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
                     || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
-            // Move the task
-            sourceStack.removeTask(this, reason, moveStackToFront
-                    ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
-            toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason);
+
+            reparent(toStack.getTaskStack(), position, moveStackToFront, reason);
 
             if (schedulePictureInPictureModeChange) {
                 // Notify of picture-in-picture mode changes
                 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
             }
 
-            // TODO: Ensure that this is actually necessary here
-            // Notify the voice session if required
-            if (voiceSession != null) {
-                try {
-                    voiceSession.taskStarted(intent, mTaskId);
-                } catch (RemoteException e) {
-                }
-            }
-
             // If the task had focus before (or we're requested to move focus), move focus to the
             // new stack by moving the stack to the front.
             if (r != null) {
@@ -809,14 +686,6 @@
                 || targetWindowingMode == WINDOWING_MODE_FREEFORM;
     }
 
-    void cancelWindowTransition() {
-        if (mTask == null) {
-            Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found.");
-            return;
-        }
-        mTask.cancelTaskWindowTransition();
-    }
-
     /**
      * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
      */
@@ -970,67 +839,105 @@
         return (T) mStack;
     }
 
-    /**
-     * Must be used for setting parent stack because it performs configuration updates.
-     * Must be called after adding task as a child to the stack.
-     */
-    // TODO(task-unify): Remove or rework after task level unification.
-    void setStack(ActivityStack stack) {
-        if (stack != null && !stack.isInStackLocked(this)) {
-            throw new IllegalStateException("Task must be added as a Stack child first.");
-        }
-        final ActivityStack oldStack = mStack;
-        mStack = stack;
+    // TODO(stack-unify): Can be removed on stack unified.
+    void onParentChanged(ActivityStack newParent, ActivityStack oldParent) {
+        onParentChanged(
+                newParent != null ? newParent.mTaskStack : null,
+                oldParent != null ? oldParent.mTaskStack : null);
+    }
 
-        // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this
-        // {@link ActivityRecord} from its current {@link ActivityStack}.
+    @Override
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        final ActivityStack oldStack = (oldParent != null)
+                ? ((TaskStack) oldParent).mActivityStack : null;
+        final ActivityStack newStack = (newParent != null)
+                ? ((TaskStack) newParent).mActivityStack : null;
 
-        if (oldStack != mStack) {
+        mStack = newStack;
+
+        super.onParentChanged(newParent, oldParent);
+
+        if (oldStack != null) {
             for (int i = getChildCount() - 1; i >= 0; --i) {
                 final ActivityRecord activity = getChildAt(i);
+                oldStack.onActivityRemovedFromStack(activity);
+            }
 
-                if (oldStack != null) {
-                    oldStack.onActivityRemovedFromStack(activity);
-                }
+            updateTaskMovement(true /*toFront*/);
 
-                if (mStack != null) {
-                    stack.onActivityAddedToStack(activity);
+            if (oldStack.inPinnedWindowingMode()
+                    && (newStack == null || !newStack.inPinnedWindowingMode())) {
+                // Notify if a task from the pinned stack is being removed
+                // (or moved depending on the mode).
+                mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
+            }
+        }
+
+        if (newStack != null) {
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityRecord activity = getChildAt(i);
+                newStack.onActivityAddedToStack(activity);
+            }
+
+            // TODO: Ensure that this is actually necessary here
+            // Notify the voice session if required
+            if (voiceSession != null) {
+                try {
+                    voiceSession.taskStarted(intent, mTaskId);
+                } catch (RemoteException e) {
                 }
             }
         }
 
-        onParentChanged(mStack, oldStack);
+        // First time we are adding the task to the system.
+        if (oldParent == null && newParent != null) {
+
+            // TODO: Super random place to be doing this, but aligns with what used to be done
+            // before we unified Task level. Look into if this can be done in a better place.
+            updateOverrideConfigurationFromLaunchBounds();
+        }
+
+        // Task is being removed.
+        if (oldParent != null && newParent == null) {
+            cleanUpResourcesForDestroy();
+        }
+
+
+        // Update task bounds if needed.
+        adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
+
+        if (getWindowConfiguration().windowsAreScaleable()) {
+            // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
+            // while a resize is pending.
+            forceWindowsScaleable(true /* force */);
+        } else {
+            forceWindowsScaleable(false /* force */);
+        }
+
+        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+    }
+
+    /** TODO(task-merge): Consolidate into {@link TaskStack#onChildPositionChanged}. */
+    void updateTaskMovement(boolean toFront) {
+        if (isPersistable) {
+            mLastTimeMoved = System.currentTimeMillis();
+            // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
+            // recently will be most negative, tasks sent to the bottom before that will be less
+            // negative. Similarly for recent tasks moved to the top which will be most positive.
+            if (!toFront) {
+                mLastTimeMoved *= -1;
+            }
+        }
+        mAtmService.mRootActivityContainer.invalidateTaskLayers();
     }
 
     /**
-     * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set.
+     * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
      */
     int getStackId() {
         return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
     }
 
-    @Override
-    protected int getChildCount() {
-        return mActivities.size();
-    }
-
-    @Override
-    protected ActivityRecord getChildAt(int index) {
-        return mActivities.get(index);
-    }
-
-    @Override
-    protected ConfigurationContainer getParent() {
-        return mStack;
-    }
-
-    @Override
-    protected void onParentChanged(
-            ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        super.onParentChanged(newParent, oldParent);
-        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
-    }
-
     // Close up recents linked list.
     private void closeRecentsChain() {
         if (mPrevAffiliate != null) {
@@ -1121,16 +1028,6 @@
         return null;
     }
 
-    boolean isVisible() {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.visible) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Return true if any activities in this task belongs to input uid.
      */
@@ -1210,15 +1107,10 @@
      * Reorder the history stack so that the passed activity is brought to the front.
      */
     final void moveActivityToFrontLocked(ActivityRecord newTop) {
-        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
-                "Removing and adding activity " + newTop
-                + " to stack at top callers=" + Debug.getCallers(4));
+        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
+                + newTop + " to stack at top callers=" + Debug.getCallers(4));
 
-        mActivities.remove(newTop);
-        mActivities.add(newTop);
-
-        // Make sure window manager is aware of the position change.
-        mTask.positionChildAtTop(newTop);
+        positionChildAtTop(newTop);
         updateEffectiveIntent();
     }
 
@@ -1232,19 +1124,29 @@
         return getChildAt(0).getActivityType();
     }
 
-    /** Called when a Task child is added from the Task.java side. */
-    // TODO(task-unify): Just override addChild to do what is needed when someone calls to add a
-    // child.
-    void onChildAdded(ActivityRecord r, int index) {
+    @Override
+    void addChild(ActivityRecord r, int index) {
+        if (r.getParent() != null) {
+            // Shouldn't already have a parent since we are just adding to the task...Maybe you
+            // meant to use reparent?
+            throw new IllegalStateException(
+                    "r=" + r + " parent=" + r.getParent() + " task=" + this);
+        }
+
+        // If this task had any child before we added this one.
+        boolean hadChild = hasChild();
+
+        index = getAdjustedAddPosition(r, index);
+        super.addChild(r, index);
+
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
         r.inHistory = true;
 
-        // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
-        if (!mActivities.remove(r) && r.occludesParent()) {
-            // Was not previously in list.
+        if (r.occludesParent()) {
             numFullscreen++;
         }
         // Only set this based on the first activity
-        if (!hasChild()) {
+        if (!hadChild) {
             if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
                 // Normally non-standard activity type for the activity record will be set when the
                 // object is created, however we delay setting the standard application type until
@@ -1264,20 +1166,6 @@
             r.setActivityType(getActivityType());
         }
 
-        final int size = getChildCount();
-
-        if (index == size && size > 0) {
-            final ActivityRecord top = getChildAt(size - 1);
-            if (top.mTaskOverlay) {
-                // Place below the task overlay activity since the overlay activity should always
-                // be on top.
-                index--;
-            }
-        }
-
-        index = Math.min(size, index);
-        mActivities.add(index, r);
-
         updateEffectiveIntent();
         if (r.isPersistable()) {
             mAtmService.notifyTaskPersisterLocked(this, false);
@@ -1288,31 +1176,23 @@
         mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
     }
 
-    // TODO(task-unify): Merge onChildAdded method below into this since task will be a single
-    //  object.
     void addChild(ActivityRecord r) {
-        if (r.getParent() != null) {
-            // Shouldn't already have a parent since we are just adding to the task...
-            throw new IllegalStateException(
-                    "r=" + r + " parent=" + r.getParent() + " task=" + this);
-        }
-
-        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
-        // This means the activity isn't attached to Task.java yet. Go ahead and do that.
-        // TODO(task-unify): Remove/call super once we unify task level.
-        if (mTask != null) {
-            mTask.addChild(r, Integer.MAX_VALUE /* add on top */);
-        } else {
-            onChildAdded(r, Integer.MAX_VALUE);
-        }
+        addChild(r, Integer.MAX_VALUE /* add on top */);
     }
 
-    /** Called when a Task child is removed from the Task.java side. */
-    // TODO(task-unify): Just override removeChild to do what is needed when someone calls to remove
-    // a child.
-    void onChildRemoved(ActivityRecord r) {
-        if (mActivities.remove(r) && r.occludesParent()) {
-            // Was previously in list.
+    @Override
+    void removeChild(ActivityRecord r) {
+        removeChild(r, "removeChild");
+    }
+
+    void removeChild(ActivityRecord r, String reason) {
+        if (!mChildren.contains(r)) {
+            Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
+            return;
+        }
+
+        super.removeChild(r);
+        if (r.occludesParent()) {
             numFullscreen--;
         }
         if (r.isPersistable()) {
@@ -1336,16 +1216,19 @@
                 // When destroying a task, tell the supervisor to remove it so that any activity it
                 // has can be cleaned up correctly. This is currently the only place where we remove
                 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
-                // state into removeTask(), we just clear the task here before the other residual
+                // state into removeChild(), we just clear the task here before the other residual
                 // work.
-                // TODO: If the callers to removeTask() changes such that we have multiple places
-                //       where we are destroying the task, move this back into removeTask()
+                // TODO: If the callers to removeChild() changes such that we have multiple places
+                //       where we are destroying the task, move this back into removeChild()
                 mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
-                        !REMOVE_FROM_RECENTS, "onChildRemoved");
+                        !REMOVE_FROM_RECENTS, reason);
             }
         } else if (!mReuseTask) {
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
-            mStack.removeTask(this, "onChildRemoved", REMOVE_TASK_MODE_DESTROYING);
+            mStack.removeChild(this, reason);
+            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
+                    "removeChild: last r=" + r + " in t=" + this);
+            removeIfPossible();
         }
     }
 
@@ -1380,7 +1263,7 @@
      * Completely remove all activities associated with an existing
      * task starting at a specified index.
      */
-    final void performClearTaskAtIndexLocked(int activityNdx, String reason) {
+    private void performClearTaskAtIndexLocked(int activityNdx, String reason) {
         int numActivities = getChildCount();
         for ( ; activityNdx < numActivities; ++activityNdx) {
             final ActivityRecord r = getChildAt(activityNdx);
@@ -1390,7 +1273,7 @@
             if (mStack == null) {
                 // Task was restored from persistent storage.
                 r.takeFromHistory();
-                mActivities.remove(activityNdx);
+                removeChild(r);
                 --activityNdx;
                 --numActivities;
             } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
@@ -1526,20 +1409,13 @@
                 " mLockTaskAuth=" + lockTaskAuthToString());
     }
 
-    private boolean isResizeable(boolean checkSupportsPip) {
-        return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
-                || (checkSupportsPip && mSupportsPictureInPicture));
-    }
-
-    boolean isResizeable() {
-        return isResizeable(true /* checkSupportsPip */);
-    }
-
     @Override
     public boolean supportsSplitScreenWindowingMode() {
         // A task can not be docked even if it is considered resizeable because it only supports
         // picture-in-picture mode but has a non-resizeable resizeMode
         return super.supportsSplitScreenWindowingMode()
+                // TODO(task-group): Probably makes sense to move this and associated code into
+                // WindowContainer so it affects every node.
                 && mAtmService.mSupportsSplitScreenMultiWindow
                 && (mAtmService.mForceResizableActivities
                         || (isResizeable(false /* checkSupportsPip */)
@@ -1672,15 +1548,13 @@
                 }
                 topActivity = false;
             }
-            mTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
-                    colorPrimary, colorBackground, statusBarColor, navigationBarColor,
+            final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
+                    iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
                     statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent);
-            if (mTask != null) {
-                mTask.setTaskDescription(mTaskDescription);
-            }
+            setTaskDescription(taskDescription);
             // Update the task affiliation color if we are the parent of the group
             if (mTaskId == mAffiliatedTaskId) {
-                mAffiliatedTaskColor = mTaskDescription.getPrimaryColor();
+                mAffiliatedTaskColor = taskDescription.getPrimaryColor();
             }
         }
     }
@@ -1903,38 +1777,6 @@
     }
 
     /**
-     * Displayed bounds are used to set where the task is drawn at any given time. This is
-     * separate from its actual bounds so that the app doesn't see any meaningful configuration
-     * changes during transitionary periods.
-     */
-    void setDisplayedBounds(Rect bounds) {
-        if (bounds == null) {
-            mDisplayedBounds.setEmpty();
-        } else {
-            mDisplayedBounds.set(bounds);
-        }
-        if (mTask != null) {
-            mTask.setOverrideDisplayedBounds(
-                    mDisplayedBounds.isEmpty() ? null : mDisplayedBounds);
-        }
-    }
-
-    /**
-     * Gets the current overridden displayed bounds. These will be empty if the task is not
-     * currently overriding where it is displayed.
-     */
-    Rect getDisplayedBounds() {
-        return mDisplayedBounds;
-    }
-
-    /**
-     * @return {@code true} if this has overridden displayed bounds.
-     */
-    boolean hasDisplayedBounds() {
-        return !mDisplayedBounds.isEmpty();
-    }
-
-    /**
      * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
      * intersectBounds on a side, then the respective side will not be intersected.
      *
@@ -2190,16 +2032,10 @@
         computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
     }
 
-    /** @see WindowContainer#handlesOrientationChangeFromDescendant */
-    boolean handlesOrientationChangeFromDescendant() {
-        return mTask != null && mTask.getParent() != null
-                && mTask.getParent().handlesOrientationChangeFromDescendant();
-    }
-
     /**
-     * Compute bounds (letterbox or pillarbox) for {@link #WINDOWING_MODE_FULLSCREEN} when the
-     * parent doesn't handle the orientation change and the requested orientation is different from
-     * the parent.
+     * Compute bounds (letterbox or pillarbox) for
+     * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
+     * orientation change and the requested orientation is different from the parent.
      */
     void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
             @NonNull Rect parentBounds, int parentOrientation) {
@@ -2345,7 +2181,7 @@
         info.realActivity = realActivity;
         info.numActivities = mReuseActivitiesReport.numActivities;
         info.lastActiveTime = lastActiveTime;
-        info.taskDescription = new ActivityManager.TaskDescription(mTaskDescription);
+        info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
         info.resizeMode = mResizeMode;
         info.configuration.setTo(getConfiguration());
@@ -2435,7 +2271,7 @@
                     }
                     pw.println(")");
         }
-        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
+        pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
         if (!askedCompatMode || !inRecents || !isAvailable) {
             pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
                     pw.print(" inRecents="); pw.print(inRecents);
@@ -2490,6 +2326,7 @@
         return toString();
     }
 
+    @Override
     public void writeToProto(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
@@ -2497,13 +2334,13 @@
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
+        writeToProtoInnerTaskOnly(proto, TASK, logLevel);
         proto.write(ID, mTaskId);
         for (int i = getChildCount() - 1; i >= 0; i--) {
-            ActivityRecord activity = getChildAt(i);
+            final ActivityRecord activity = getChildAt(i);
             activity.writeToProto(proto, ACTIVITIES);
         }
-        proto.write(STACK_ID, mStack.mStackId);
+        proto.write(STACK_ID, getStackId());
         if (mLastNonFullscreenBounds != null) {
             mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
         }
@@ -2579,8 +2416,8 @@
         if (lastDescription != null) {
             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
         }
-        if (mTaskDescription != null) {
-            mTaskDescription.saveToXml(out);
+        if (getTaskDescription() != null) {
+            getTaskDescription().saveToXml(out);
         }
         out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
@@ -2641,14 +2478,14 @@
 
     static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
             Intent intent, IVoiceInteractionSession voiceSession,
-            IVoiceInteractor voiceInteractor) {
+            IVoiceInteractor voiceInteractor, ActivityStack stack) {
         return getTaskRecordFactory().create(
-                service, taskId, info, intent, voiceSession, voiceInteractor);
+                service, taskId, info, intent, voiceSession, voiceInteractor, stack);
     }
 
     static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-            Intent intent, TaskDescription taskDescription) {
-        return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription);
+            Intent intent, TaskDescription taskDescription, ActivityStack stack) {
+        return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription, stack);
     }
 
     static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
@@ -2665,15 +2502,15 @@
 
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
                 Intent intent, IVoiceInteractionSession voiceSession,
-                IVoiceInteractor voiceInteractor) {
+                IVoiceInteractor voiceInteractor, ActivityStack stack) {
             return new TaskRecord(service, taskId, info, intent, voiceSession, voiceInteractor,
-                    null /*taskDescription*/);
+                    null /*taskDescription*/, stack);
         }
 
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent, TaskDescription taskDescription) {
+                Intent intent, TaskDescription taskDescription, ActivityStack stack) {
             return new TaskRecord(service, taskId, info, intent, null /*voiceSession*/,
-                    null /*voiceInteractor*/, taskDescription);
+                    null /*voiceInteractor*/, taskDescription, stack);
         }
 
         /**
@@ -2683,20 +2520,20 @@
                 Intent affinityIntent, String affinity, String rootAffinity,
                 ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
                 boolean autoRemoveRecents, boolean askedCompatMode, int userId,
-                int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities,
+                int effectiveUid, String lastDescription,
                 long lastTimeMoved, boolean neverRelinquishIdentity,
                 TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
                 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
                 int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
-                boolean userSetupComplete, int minWidth, int minHeight) {
+                boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
             return new TaskRecord(service, taskId, intent, affinityIntent, affinity,
                     rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
-                    askedCompatMode, userId, effectiveUid, lastDescription, activities,
+                    askedCompatMode, userId, effectiveUid, lastDescription,
                     lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
                     prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
                     resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
                     minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
-                    null /*_voiceInteractor*/);
+                    null /*_voiceInteractor*/, stack);
         }
 
         TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
@@ -2908,15 +2745,15 @@
                     taskId, intent, affinityIntent,
                     affinity, rootAffinity, realActivity, origActivity, rootHasReset,
                     autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
-                    activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
+                    lastTimeOnTop, neverRelinquishIdentity, taskDescription,
                     taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
                     callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
-                    userSetupComplete, minWidth, minHeight);
+                    userSetupComplete, minWidth, minHeight, null /*stack*/);
             task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
             task.setBounds(lastNonFullscreenBounds);
 
             for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
-                activities.get(activityNdx).setTask(task);
+                task.addChild(activities.get(activityNdx));
             }
 
             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 56211e2..68b76fb 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -116,7 +116,6 @@
 
     /** ActivityRecords that are exiting, but still on screen for animations. */
     final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
-    final ArrayList<ActivityRecord> mTmpActivities = new ArrayList<>();
 
     /** Detach this stack from its display when animation completes. */
     // TODO: maybe tie this to WindowContainer#removeChild some how...
@@ -330,7 +329,7 @@
     }
 
     /** Bounds of the stack with other system factors taken into consideration. */
-    public void getDimBounds(Rect out) {
+    void getDimBounds(Rect out) {
         getBounds(out);
     }
 
@@ -482,11 +481,6 @@
                 dividerSize);
     }
 
-    // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC.
-    void addTask(Task task, int position) {
-        addTask(task, position, task.showForAllUsers(), true /* moveParents */);
-    }
-
     /**
      * Put a Task in this stack. Used for adding only.
      * When task is added to top of the stack, the entire branch of the hierarchy (including stack
@@ -495,22 +489,21 @@
      * @param position Target position to add the task to.
      * @param showForAllUsers Whether to show the task regardless of the current user.
      */
-    void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
-        final TaskStack currentStack = task.mStack;
-        // TODO: We pass stack to task's constructor, but we still need to call this method.
-        // This doesn't make sense, mStack will already be set equal to "this" at this point.
-        if (currentStack != null && currentStack.mStackId != mStackId) {
-            throw new IllegalStateException("Trying to add taskId=" + task.mTaskId
-                    + " to stackId=" + mStackId
-                    + ", but it is already attached to stackId=" + task.mStack.mStackId);
-        }
-
+    void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) {
         // Add child task.
         task.mStack = this;
         addChild(task, null);
 
         // Move child to a proper position, as some restriction for position might apply.
-        positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
+        position = positionChildAt(
+                position, task, moveParents /* includingParents */, showForAllUsers);
+        // TODO(task-merge): Remove cast.
+        mActivityStack.onChildAdded((TaskRecord) task, position);
+    }
+
+    @Override
+    void addChild(Task task, int position) {
+        addChild(task, position, task.showForAllUsers(), false /* includingParents */);
     }
 
     void positionChildAt(Task child, int position) {
@@ -563,13 +556,12 @@
 
     /**
      * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in
-     * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive
-     * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}.
+     * {@link TaskStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can receive
+     * showForAllUsers param from {@link ActivityRecord} instead of {@link Task#showForAllUsers()}.
      */
-    private void positionChildAt(int position, Task child, boolean includingParents,
+    int positionChildAt(int position, Task child, boolean includingParents,
             boolean showForAllUsers) {
-        final int targetPosition = findPositionForTask(child, position, showForAllUsers,
-                false /* addingNew */);
+        final int targetPosition = findPositionForTask(child, position, showForAllUsers);
         super.positionChildAt(targetPosition, child, includingParents);
 
         // Log positioning.
@@ -578,6 +570,14 @@
 
         final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
+
+        return targetPosition;
+    }
+
+    @Override
+    void onChildPositionChanged(WindowContainer child) {
+        // TODO(task-merge): Read comment on updateTaskMovement method.
+        //((TaskRecord) child).updateTaskMovement(true);
     }
 
     void reparent(int displayId, Rect outStackBounds, boolean onTop) {
@@ -597,14 +597,13 @@
 
     // TODO: We should really have users as a window container in the hierarchy so that we don't
     // have to do complicated things like we are doing in this method.
-    private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
-            boolean addingNew) {
+    private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers) {
         final boolean canShowTask =
                 showForAllUsers || mWmService.isCurrentProfileLocked(task.mUserId);
 
         final int stackSize = mChildren.size();
         int minPosition = 0;
-        int maxPosition = addingNew ? stackSize : stackSize - 1;
+        int maxPosition = stackSize - 1;
 
         if (canShowTask) {
             minPosition = computeMinPosition(minPosition, stackSize);
@@ -615,8 +614,7 @@
         // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
         if (targetPosition == POSITION_BOTTOM && minPosition == 0) {
             return POSITION_BOTTOM;
-        } else if (targetPosition == POSITION_TOP
-                && maxPosition == (addingNew ? stackSize : stackSize - 1)) {
+        } else if (targetPosition == POSITION_TOP && maxPosition == (stackSize - 1)) {
             return POSITION_TOP;
         }
         // Reset position based on minimum/maximum possible positions.
@@ -669,24 +667,17 @@
      */
     @Override
     void removeChild(Task task) {
+        if (!mChildren.contains(task)) {
+            // Not really in this stack anymore...
+            return;
+        }
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task);
 
         super.removeChild(task);
         task.mStack = null;
 
-        if (mDisplayContent != null) {
-            if (mChildren.isEmpty()) {
-                getParent().positionChildAt(POSITION_BOTTOM, this, false /* includingParents */);
-            }
-            mDisplayContent.setLayoutNeeded();
-        }
-        for (int appNdx = mExitingActivities.size() - 1; appNdx >= 0; --appNdx) {
-            final ActivityRecord activity = mExitingActivities.get(appNdx);
-            if (activity.getTask() == task) {
-                activity.mIsExiting = false;
-                mExitingActivities.remove(appNdx);
-            }
-        }
+        // TODO(task-merge): Remove cast.
+        mActivityStack.onChildRemoved((TaskRecord) task, mDisplayContent);
     }
 
     @Override
@@ -1298,7 +1289,7 @@
         super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
         proto.write(ID, mStackId);
         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
-            mChildren.get(taskNdx).writeToProto(proto, TASKS, logLevel);
+            mChildren.get(taskNdx).writeToProtoInnerTaskOnly(proto, TASKS, logLevel);
         }
         proto.write(FILLS_PARENT, matchParentBounds());
         getRawBounds().writeToProto(proto, BOUNDS);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 7ce2b5e..a393ba6 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -428,7 +428,7 @@
             parent.mTreeWeight += child.mTreeWeight;
             parent = parent.getParent();
         }
-        onChildPositionChanged();
+        onChildPositionChanged(child);
     }
 
     /**
@@ -454,7 +454,7 @@
             parent.mTreeWeight -= child.mTreeWeight;
             parent = parent.getParent();
         }
-        onChildPositionChanged();
+        onChildPositionChanged(child);
     }
 
     /**
@@ -583,7 +583,7 @@
                 if (mChildren.peekLast() != child) {
                     mChildren.remove(child);
                     mChildren.add(child);
-                    onChildPositionChanged();
+                    onChildPositionChanged(child);
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -594,7 +594,7 @@
                 if (mChildren.peekFirst() != child) {
                     mChildren.remove(child);
                     mChildren.addFirst(child);
-                    onChildPositionChanged();
+                    onChildPositionChanged(child);
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
@@ -608,14 +608,14 @@
                 //       doing this adjustment here and remove any adjustments in the callers.
                 mChildren.remove(child);
                 mChildren.add(position, child);
-                onChildPositionChanged();
+                onChildPositionChanged(child);
         }
     }
 
     /**
      * Notify that a child's position has changed. Possible changes are adding or removing a child.
      */
-    void onChildPositionChanged() { }
+    void onChildPositionChanged(WindowContainer child) { }
 
     /**
      * Update override configuration and recalculate full config.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2009dbd..ef9e69d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -439,7 +439,7 @@
 
             // In case the runtime switched since last boot (such as when
             // the old runtime was removed in an OTA), set the system
-            // property so that it is in sync. We can | xq oqi't do this in
+            // property so that it is in sync. We can't do this in
             // libnativehelper's JniInvocation::Init code where we already
             // had to fallback to a different runtime because it is
             // running as root and we need to be the system user to set
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 38d6c9c..2ce37f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -53,8 +53,6 @@
 import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
@@ -136,13 +134,13 @@
 
     @Test
     public void testStackCleanupOnActivityRemoval() {
-        mTask.mTask.removeChild(mActivity);
+        mTask.removeChild(mActivity);
         verify(mStack, times(1)).onActivityRemovedFromStack(any());
     }
 
     @Test
     public void testStackCleanupOnTaskRemoval() {
-        mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING);
+        mStack.removeChild(mTask, null /*reason*/);
         // Stack should be gone on task removal.
         assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId));
     }
@@ -325,7 +323,7 @@
                 : ORIENTATION_PORTRAIT;
         mTask.onRequestedOverrideConfigurationChanged(newConfig);
 
-        doReturn(true).when(mTask.mTask).isDragResizing();
+        doReturn(true).when(mTask).isDragResizing();
 
         mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 
@@ -382,7 +380,7 @@
         }
 
         // Mimic the behavior that display doesn't handle app's requested orientation.
-        final DisplayContent dc = mTask.mTask.getDisplayContent();
+        final DisplayContent dc = mTask.getDisplayContent();
         doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
         doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
 
@@ -1174,7 +1172,7 @@
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
         for (TaskRecord t : homeStack.getAllTasks()) {
-            homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING);
+            homeStack.removeChild(t, "test");
         }
         mActivity.finishing = true;
         doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
@@ -1200,7 +1198,7 @@
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
         for (TaskRecord t : homeStack.getAllTasks()) {
-            homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING);
+            homeStack.removeChild(t, "test");
         }
         mActivity.finishing = true;
         spyOn(mStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index fcebb81..cc0cc3f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -38,7 +38,6 @@
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
@@ -93,21 +92,6 @@
     }
 
     @Test
-    public void testEmptyTaskCleanupOnRemove() {
-        assertNotNull(mTask.getTask());
-        mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING);
-        assertNull(mTask.getTask());
-    }
-
-    @Test
-    public void testOccupiedTaskCleanupOnRemove() {
-        final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
-        assertNotNull(mTask.getTask());
-        mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING);
-        assertNotNull(mTask.getTask());
-    }
-
-    @Test
     public void testResumedActivity() {
         final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
         assertNull(mStack.getResumedActivity());
@@ -996,27 +980,6 @@
     }
 
     @Test
-    public void testAdjustFocusedStackToHomeWhenNoActivity() {
-        final ActivityStack homeStask = mDefaultDisplay.getHomeStack();
-        TaskRecord homeTask = homeStask.topTask();
-        if (homeTask == null) {
-            // Create home task if there isn't one.
-            homeTask = new TaskBuilder(mSupervisor).setStack(homeStask).build();
-        }
-
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        mStack.moveToFront("testAdjustFocusedStack");
-
-        // Simulate that home activity has not been started or is force-stopped.
-        homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING);
-
-        // Finish the only activity.
-        topActivity.finishIfPossible("testAdjustFocusedStack", false /* oomAdj */);
-        // Although home stack is empty, it should still be the focused stack.
-        assertEquals(homeStask, mDefaultDisplay.getFocusedStack());
-    }
-
-    @Test
     public void testWontFinishHomeStackImmediately() {
         final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ace5d4e..a28bbb6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -715,7 +715,7 @@
         if (startedActivity != null && startedActivity.getTaskRecord() != null) {
             // Remove the activity so it doesn't interfere with with subsequent activity launch
             // tests from this method.
-            startedActivity.getTaskRecord().mTask.removeChild(startedActivity);
+            startedActivity.getTaskRecord().removeChild(startedActivity);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 78db6c9..1db8f1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -269,7 +269,7 @@
                 // fullscreen value is normally read from resources in ctor, so for testing we need
                 // to set it somewhere else since we can't mock resources.
                 doReturn(true).when(activity).occludesParent();
-                activity.setTask(mTaskRecord);
+                mTaskRecord.addChild(activity);
                 // Make visible by default...
                 activity.setHidden(false);
             }
@@ -376,15 +376,13 @@
 
             final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
                     intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
-                    null /*taskDescription*/);
+                    null /*taskDescription*/, mStack);
             spyOn(task);
             task.mUserId = mUserId;
 
             if (mStack != null) {
                 mStack.moveToFront("test");
-                mStack.addTask(task, true, "creating test task");
-                task.createTask(true, true);
-                spyOn(task.mTask);
+                mStack.addChild(task, true, true);
             }
 
             return task;
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 1fb6a56..c5301b8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -165,7 +165,7 @@
         // setup currently defaults to no snapshot.
         setUpOnDisplay(mDisplayContent);
 
-        mTask.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
         assertEquals(1, mDisplayContent.mChangingApps.size());
         assertTrue(mActivity.isInChangeTransition());
 
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 2f0486d..d33dbd1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -48,7 +48,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
 import android.content.res.Configuration;
@@ -63,7 +63,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 
 /**
  * Tests for the {@link ActivityRecord} class.
@@ -209,9 +208,11 @@
 
     @Test
     public void testSizeCompatBounds() {
+        // TODO(task-merge): Move once Task is merged into TaskRecord
+        final TaskRecord tr = (TaskRecord) mTask;
         // Disable the real configuration resolving because we only simulate partial flow.
         // TODO: Have test use full flow.
-        doNothing().when(mTask.mTaskRecord).computeConfigResourceOverrides(any(), any());
+        doNothing().when(tr).computeConfigResourceOverrides(any(), any());
         final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
@@ -337,11 +338,9 @@
 
         mDisplayContent.getDisplayRotation().setFixedToUserRotation(
                 DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
-
-        mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS);
+        reset(mTask);
         mActivity.reportDescendantOrientationChangeIfNeeded();
-
-        verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class));
+        verify(mTask).onConfigurationChanged(any(Configuration.class));
     }
 
     @Test
@@ -451,6 +450,7 @@
 
     @Test
     public void testTransitionAnimationBounds() {
+        removeGlobalMinSizeRestriction();
         final Rect stackBounds = new Rect(0, 0, 1000, 600);
         final Rect taskBounds = new Rect(100, 400, 600, 800);
         mStack.setBounds(stackBounds);
@@ -458,16 +458,16 @@
 
         // Check that anim bounds for freeform window match task bounds
         mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_NONE));
+        assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_NONE));
 
         // STACK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by
         // bounds animation layer.
         mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
+        assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
 
         // STACK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later.
         mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-        assertEquals(stackBounds, mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
+        assertEquals(mStack.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index cc598ff..69091c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -885,7 +885,7 @@
         final int taskId = task.mTaskId;
         mRecentTasks.add(task);
         // Only keep the task in RecentTasks.
-        task.removeWindowContainer();
+        task.removeIfPossible();
         mStack.remove();
 
         // The following APIs should not restore task from recents to the active list.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 839ddb2..ca8f535 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -196,9 +196,6 @@
         doReturn(app).when(mService).getProcessController(eq(recentActivity.processName), anyInt());
         ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
         doNothing().when(lifecycleManager).scheduleTransaction(any());
-        AppWarnings appWarnings = mService.getAppWarningsLocked();
-        spyOn(appWarnings);
-        doNothing().when(appWarnings).onStartActivity(any());
 
         startRecentsActivity();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index aa97de72..63f70c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -36,7 +36,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
 
@@ -272,8 +271,7 @@
         assertTrue(pinnedActivity.isFocusable());
 
         // Without the overridding activity, stack should not be focusable.
-        pinnedStack.removeTask(pinnedActivity.getTaskRecord(), "testFocusability",
-                REMOVE_TASK_MODE_DESTROYING);
+        pinnedStack.removeChild(pinnedActivity.getTaskRecord(), "testFocusability");
         assertFalse(pinnedStack.isFocusable());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index fa1f435..ad1d1af 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -437,6 +437,10 @@
             spyOn(getLockTaskController());
             spyOn(getTaskChangeNotificationController());
             initRootActivityContainerMocks();
+
+            AppWarnings appWarnings = getAppWarningsLocked();
+            spyOn(appWarnings);
+            doNothing().when(appWarnings).onStartActivity(any());
         }
 
         void initRootActivityContainerMocks() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index df55b39..012eb52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -79,8 +79,9 @@
         // This should be the same calculation as the TaskPositioner uses.
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
+        removeGlobalMinSizeRestriction();
 
-        mPositioner = new TaskPositioner(mWm, mock(IActivityTaskManager.class));
+        mPositioner = new TaskPositioner(mWm, mWm.mAtmService);
         mPositioner.register(mDisplayContent);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
@@ -493,10 +494,7 @@
                         + ") " + Log.getStackTraceString(new Throwable()));
             }
         }
-        assertEquals("left", expected.left, actual.left);
-        assertEquals("right", expected.right, actual.right);
-        assertEquals("top", expected.top, actual.top);
-        assertEquals("bottom", expected.bottom, actual.bottom);
+        assertEquals(expected, actual);
     }
 
     @FlakyTest(bugId = 129492888)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index f8d49ad..d2342f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -66,7 +66,8 @@
                 any(InputChannel.class))).thenReturn(true);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
-        mWindow.getTask().setResizeable(RESIZE_MODE_RESIZEABLE);
+        // TODO(task-merge): Remove cast.
+        ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_RESIZEABLE);
         mWindow.mInputChannel = new InputChannel();
         mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
@@ -142,7 +143,8 @@
         doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt());
         assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
 
-        mWindow.getTask().setResizeable(RESIZE_MODE_UNRESIZEABLE);
+        // TODO(task-merge): Remove cast.
+        ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_UNRESIZEABLE);
 
         mTarget.handleTapOutsideTask(content, 0, 0);
         // Wait until the looper processes finishTaskPositioning.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index a4e38f1..2cafc96 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -132,7 +132,7 @@
     @Test
     public void testCopyBaseIntentForTaskInfo() {
         final TaskRecord task = createTaskRecord(1);
-        task.mTaskDescription = new ActivityManager.TaskDescription();
+        task.setTaskDescription(new ActivityManager.TaskDescription());
         final TaskInfo info = task.getTaskInfo();
 
         // The intent of info should be a copy so assert that they are different instances.
@@ -348,10 +348,12 @@
         TaskRecord task = stack.getChildAt(0);
         ActivityRecord root = task.getTopActivity();
 
-        final WindowContainer parentWindowContainer = mock(WindowContainer.class);
-        Mockito.doReturn(parentWindowContainer).when(task.mTask).getParent();
-        Mockito.doReturn(true).when(parentWindowContainer)
-                .handlesOrientationChangeFromDescendant();
+        final WindowContainer parentWindowContainer =
+                new WindowContainer(mSystemServicesTestRule.getWindowManagerService());
+        spyOn(parentWindowContainer);
+        parentWindowContainer.setBounds(fullScreenBounds);
+        doReturn(parentWindowContainer).when(task).getParent();
+        doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
 
         // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the
         // bounds because its parent says it will handle it at a later time.
@@ -433,7 +435,7 @@
         info.targetActivity = targetClassName;
 
         final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent,
-                null /* taskDescription */);
+                null /* taskDescription */, null /*stack*/);
         assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
                 task.intent.getComponent().getClassName());
 
@@ -834,8 +836,9 @@
     private TaskRecord createTaskRecord(int taskId) {
         return new TaskRecord(mService, taskId, new Intent(), null, null, null,
                 ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
-                new ArrayList<>(), 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
-                0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/);
+                0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
+                0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
+                null /*stack*/);
     }
 
     private static class TestTaskRecordFactory extends TaskRecordFactory {
@@ -843,16 +846,16 @@
 
         @Override
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent,
-                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+                Intent intent, IVoiceInteractionSession voiceSession,
+                IVoiceInteractor voiceInteractor, ActivityStack stack) {
             mCreated = true;
             return null;
         }
 
         @Override
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent,
-                ActivityManager.TaskDescription taskDescription) {
+                Intent intent, ActivityManager.TaskDescription taskDescription,
+                ActivityStack stack) {
             mCreated = true;
             return null;
         }
@@ -863,14 +866,14 @@
                 ComponentName realActivity,
                 ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents,
                 boolean askedCompatMode, int userId, int effectiveUid, String lastDescription,
-                ArrayList<ActivityRecord> activities, long lastTimeMoved,
+                long lastTimeMoved,
                 boolean neverRelinquishIdentity,
                 ActivityManager.TaskDescription lastTaskDescription,
                 int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
                 int callingUid, String callingPackage, int resizeMode,
                 boolean supportsPictureInPicture,
                 boolean realActivitySuspended, boolean userSetupComplete, int minWidth,
-                int minHeight) {
+                int minHeight, ActivityStack stack) {
             mCreated = true;
             return null;
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 4dfa266..cb2e1e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -92,7 +94,7 @@
 
         boolean gotException = false;
         try {
-            task.reparent(stackController1, 0, false/* moveParents */);
+            task.reparent(stackController1, 0, false/* moveParents */, "testReparent");
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
@@ -100,14 +102,14 @@
 
         gotException = false;
         try {
-            task.reparent(null, 0, false/* moveParents */);
+            task.reparent(null, 0, false/* moveParents */, "testReparent");
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
         assertTrue("Should not be able to reparent to a stack that doesn't exist",
                 gotException);
 
-        task.reparent(stackController2, 0, false/* moveParents */);
+        task.reparent(stackController2, 0, false/* moveParents */, "testReparent");
         assertEquals(stackController2, task.getParent());
         assertEquals(0, task.getParent().mChildren.indexOf(task));
         assertEquals(1, task2.getParent().mChildren.indexOf(task2));
@@ -125,7 +127,7 @@
         final TaskStack stack2 = createTaskStackOnDisplay(dc);
         final Task task2 = createTaskInStack(stack2, 0 /* userId */);
         // Reparent and check state
-        task.reparent(stack2, 0, false /* moveParents */);
+        task.reparent(stack2, 0, false /* moveParents */, "testReparent_BetweenDisplays");
         assertEquals(stack2, task.getParent());
         assertEquals(0, task.getParent().mChildren.indexOf(task));
         assertEquals(1, task2.getParent().mChildren.indexOf(task2));
@@ -138,6 +140,7 @@
         final Task task = createTaskInStack(stack1, 0 /* userId */);
 
         // Check that setting bounds also updates surface position
+        task.setWindowingMode(WINDOWING_MODE_FREEFORM);
         Rect bounds = new Rect(10, 10, 100, 200);
         task.setBounds(bounds);
         assertEquals(new Point(bounds.left, bounds.top), task.getLastSurfacePosition());
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 8cd97cb..428d869 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -255,6 +255,7 @@
 
     @Test
     public void testLayoutNonfullscreenTask() {
+        removeGlobalMinSizeRestriction();
         final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
         final int logicalWidth = displayInfo.logicalWidth;
         final int logicalHeight = displayInfo.logicalHeight;
@@ -264,8 +265,8 @@
         WindowState w = createWindow();
         final Task task = w.getTask();
         // Use split-screen because it is non-fullscreen, but also not floating
-        task.mTaskRecord.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        task.mTaskRecord.setBounds(taskBounds);
+        task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        task.setBounds(taskBounds);
         // The bounds we are requesting might be different from what the system resolved based on
         // other factors.
         final Rect resolvedTaskBounds = task.getBounds();
@@ -303,8 +304,8 @@
         final int insetTop = logicalHeight / 5;
         final int insetRight = insetLeft + (resolvedTaskBounds.right - resolvedTaskBounds.left);
         final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top);
-        task.mTaskRecord.setDisplayedBounds(resolvedTaskBounds);
-        task.mTaskRecord.setBounds(insetLeft, insetTop, insetRight, insetBottom);
+        task.setOverrideDisplayedBounds(resolvedTaskBounds);
+        task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
         assertEquals(resolvedTaskBounds, w.getFrameLw());
@@ -477,7 +478,7 @@
         WindowState w = createWindow();
         final Task task = w.getTask();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
-        task.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        task.setWindowingMode(WINDOWING_MODE_FREEFORM);
 
         DisplayContent dc = mTestDisplayContent;
         dc.mInputMethodTarget = w;
@@ -499,7 +500,7 @@
         // First check that it only gets moved up enough to show window.
         final Rect winRect = new Rect(200, 200, 300, 500);
 
-        task.mTaskRecord.setBounds(winRect);
+        task.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
 
@@ -511,7 +512,7 @@
 
         // Now check that it won't get moved beyond the top and then has appropriate insets
         winRect.bottom = 600;
-        task.mTaskRecord.setBounds(winRect);
+        task.setBounds(winRect);
         w.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
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 51daf65..3f32e33 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -42,7 +42,7 @@
                     .setUserId(userId)
                     .setStack(stack.mActivityStack)
                     .build();
-            return task.mTask;
+            return task;
         }
     }
 
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 780fed9..c3f59eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -384,7 +384,7 @@
     }
 
     /** Sets the default minimum task size to 1 so that tests can use small task sizes */
-    public void removeGlobalMinSizeRestriction() {
+    void removeGlobalMinSizeRestriction() {
         mWm.mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index b5e91d0..75e4fec 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2371,12 +2371,10 @@
      * @param plans the list of plans. The first plan is always the primary and
      *            most important plan. Any additional plans are secondary and
      *            may not be displayed or used by decision making logic.
-     *            The list of all plans must meet the requirements defined in
-     *            {@link SubscriptionPlan.Builder#setNetworkTypes(int[])}.
      * @throws SecurityException if the caller doesn't meet the requirements
      *             outlined above.
      * @throws IllegalArgumentException if plans don't meet the requirements
-     *             mentioned above.
+     *             defined in {@link SubscriptionPlan}.
      */
     public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) {
         try {
diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java
index e24eb26..28a5c20 100644
--- a/telephony/java/android/telephony/SubscriptionPlan.java
+++ b/telephony/java/android/telephony/SubscriptionPlan.java
@@ -44,6 +44,14 @@
  * as explaining how much mobile data they have remaining, and what will happen
  * when they run out.
  *
+ * If specifying network types, the developer must supply at least one plan
+ * that applies to all network types (default), and all additional plans
+ * may not include a particular network type more than once.
+ * This is enforced by {@link SubscriptionManager} when setting the plans.
+ *
+ * Plan selection will prefer plans that have specific network types defined
+ * over plans that apply to all network types.
+ *
  * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List)
  * @see SubscriptionManager#getSubscriptionPlans(int)
  */
@@ -213,7 +221,7 @@
 
     /**
      * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to.
-     * A null array means this SubscriptionPlan applies to all network types.
+     * A null value means this SubscriptionPlan applies to all network types.
      */
     public @Nullable @NetworkType int[] getNetworkTypes() {
         return networkTypes;
@@ -372,20 +380,13 @@
 
         /**
          * Set the network types this SubscriptionPlan applies to.
-         * The developer must supply at least one plan that applies to all network types (default),
-         * and all additional plans may not include a particular network type more than once.
-         * Plan selection will prefer plans that have specific network types defined
-         * over plans that apply to all network types.
          *
          * @param networkTypes a set of all {@link NetworkType}s that apply to this plan.
-         *            A null value or empty array means the plan applies to all network types.
+         *            A null value means the plan applies to all network types,
+         *            and an empty array means the plan applies to no network types.
          */
         public @NonNull Builder setNetworkTypes(@Nullable @NetworkType int[] networkTypes) {
-            if (networkTypes == null || networkTypes.length == 0) {
-                plan.networkTypes = null;
-            } else {
-                plan.networkTypes = networkTypes;
-            }
+            plan.networkTypes = networkTypes;
             return this;
         }
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0c663f8..4eb5a36 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9567,18 +9567,37 @@
     }
 
     /**
-     * Resets Telephony and IMS settings back to factory defaults.
+     * Resets telephony manager settings back to factory defaults.
      *
      * @hide
      */
-    @SystemApi
-    @RequiresPermission(Manifest.permission.CONNECTIVITY_INTERNAL)
     public void factoryReset(int subId) {
         try {
             Log.d(TAG, "factoryReset: subId=" + subId);
             ITelephony telephony = getITelephony();
-            if (telephony != null)
+            if (telephony != null) {
                 telephony.factoryReset(subId);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
+
+    /**
+     * Resets Telephony and IMS settings back to factory defaults only for the subscription
+     * associated with this instance.
+     * @see #createForSubscriptionId(int)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONNECTIVITY_INTERNAL)
+    public void resetSettings() {
+        try {
+            Log.d(TAG, "resetSettings: subId=" + getSubId());
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.factoryReset(getSubId());
+            }
         } catch (RemoteException e) {
         }
     }
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 7cafa1e..9fc8e75 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -254,8 +254,8 @@
      * the {@link ImsService} associated with the subscription is not available. This can happen if
      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
      * reason.
-     * @deprecated Use {@link #registerImsRegistrationCallback(
-     * RegistrationManager.RegistrationCallback, Executor)} instead.
+     * @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor,
+     * RegistrationManager.RegistrationCallback)} instead.
      */
     @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -285,9 +285,8 @@
     /**{@inheritDoc}*/
     @Override
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void registerImsRegistrationCallback(
-            @NonNull RegistrationManager.RegistrationCallback c,
-            @NonNull @CallbackExecutor Executor executor) throws ImsException {
+    public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull RegistrationManager.RegistrationCallback c) throws ImsException {
         if (c == null) {
             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
         }
@@ -348,8 +347,8 @@
     /**{@inheritDoc}*/
     @Override
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback,
-            @NonNull @CallbackExecutor Executor executor) {
+    public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
         if (stateCallback == null) {
             throw new IllegalArgumentException("Must include a non-null callback.");
         }
@@ -371,9 +370,9 @@
     /**{@inheritDoc}*/
     @Override
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void getRegistrationTransportType(
-            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
-            @NonNull @CallbackExecutor Executor executor) {
+    public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @AccessNetworkConstants.TransportType
+                    Consumer<Integer> transportTypeCallback) {
         if (transportTypeCallback == null) {
             throw new IllegalArgumentException("Must include a non-null callback.");
         }
@@ -607,17 +606,17 @@
      * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} broadcast for this subscription.
      * @param capability The capability that is being queried for support on the carrier network.
      * @param transportType The transport type of the capability to check support for.
+     * @param executor The executor that the callback will be called with.
      * @param callback A consumer containing a Boolean result specifying whether or not the
      *                 capability is supported on this carrier network for the transport specified.
-     * @param executor The executor that the callback will be called with.
      * @throws ImsException if the subscription is no longer valid or the IMS service is not
      * available.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
             @AccessNetworkConstants.TransportType int transportType,
-            @NonNull Consumer<Boolean> callback,
-            @NonNull @CallbackExecutor Executor executor) throws ImsException {
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Boolean> callback) throws ImsException {
         if (callback == null) {
             throw new IllegalArgumentException("Must include a non-null Consumer.");
         }
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 25bd1ca..6432016 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -141,8 +141,8 @@
     /**{@inheritDoc}*/
     @Override
     public void registerImsRegistrationCallback(
-            @NonNull RegistrationManager.RegistrationCallback c,
-            @NonNull @CallbackExecutor Executor executor)
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull RegistrationCallback c)
             throws ImsException {
         if (c == null) {
             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -168,8 +168,8 @@
 
     /**{@inheritDoc}*/
     @Override
-    public void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback,
-            @NonNull @CallbackExecutor Executor executor) {
+    public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
         if (stateCallback == null) {
             throw new IllegalArgumentException("Must include a non-null stateCallback.");
         }
@@ -182,9 +182,9 @@
 
     /**{@inheritDoc}*/
     @Override
-    public void getRegistrationTransportType(
-            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
-            @NonNull @CallbackExecutor Executor executor) {
+    public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @AccessNetworkConstants.TransportType
+                    Consumer<Integer> transportTypeCallback) {
         if (transportTypeCallback == null) {
             throw new IllegalArgumentException("Must include a non-null transportTypeCallback.");
         }
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index b4c11e3..23402b8 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -90,7 +90,7 @@
 
     /**
      * Callback class for receiving IMS network Registration callback events.
-     * @see #registerImsRegistrationCallback(RegistrationCallback, Executor)
+     * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
      */
     class RegistrationCallback {
@@ -229,8 +229,8 @@
      * When the callback is registered, it will initiate the callback c to be called with the
      * current registration state.
      *
-     * @param c The {@link RegistrationCallback} to be added.
      * @param executor The executor the callback events should be run on.
+     * @param c The {@link RegistrationCallback} to be added.
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
      * @throws ImsException if the subscription associated with this callback is valid, but
      * the {@link ImsService} associated with the subscription is not available. This can happen if
@@ -238,8 +238,8 @@
      * reason.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    void registerImsRegistrationCallback(@NonNull RegistrationCallback c,
-            @NonNull @CallbackExecutor Executor executor) throws ImsException;
+    void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull RegistrationCallback c) throws ImsException;
 
     /**
      * Removes an existing {@link RegistrationCallback}.
@@ -250,36 +250,36 @@
      *
      * @param c The {@link RegistrationCallback} to be removed.
      * @see SubscriptionManager.OnSubscriptionsChangedListener
-     * @see #registerImsRegistrationCallback(RegistrationCallback, Executor)
+     * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c);
 
     /**
      * Gets the registration state of the IMS service.
-     * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
-     *                      registration state of the IMS service, which will be one of the
-     *                      following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
-     *                      {@link #REGISTRATION_STATE_REGISTERING}, or
-     *                      {@link #REGISTRATION_STATE_REGISTERED}.
      * @param executor The {@link Executor} that will be used to call the IMS registration state
      *                 callback.
+     * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
+ *                      registration state of the IMS service, which will be one of the
+ *                      following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
+ *                      {@link #REGISTRATION_STATE_REGISTERING}, or
+ *                      {@link #REGISTRATION_STATE_REGISTERED}.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback,
-            @NonNull @CallbackExecutor Executor executor);
+    void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsRegistrationState Consumer<Integer> stateCallback);
 
     /**
      * Gets the Transport Type associated with the current IMS registration.
-     * @param transportTypeCallback The transport type associated with the current IMS registration,
-     *                              which will be one of following:
-     *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
-     *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
-     *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
      * @param executor The {@link Executor} that will be used to call the transportTypeCallback.
+     * @param transportTypeCallback The transport type associated with the current IMS registration,
+ *                              which will be one of following:
+ *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
+ *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
+ *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     void getRegistrationTransportType(
-            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
-            @NonNull @CallbackExecutor Executor executor);
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback);
 }