Merge "Complete frontend APIs"
diff --git a/Android.bp b/Android.bp
index 536f688..742a70e5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -833,6 +833,7 @@
     name: "dataloader_aidl",
     srcs: [
         "core/java/android/content/pm/DataLoaderParamsParcel.aidl",
+        "core/java/android/content/pm/DataLoaderType.aidl",
         "core/java/android/content/pm/FileSystemControlParcel.aidl",
         "core/java/android/content/pm/IDataLoaderStatusListener.aidl",
         "core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl",
diff --git a/api/current.txt b/api/current.txt
index 86aa80b..0d7ce9d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3955,6 +3955,7 @@
 
   public class ActivityManager {
     method public int addAppTask(@NonNull android.app.Activity, @NonNull android.content.Intent, @Nullable android.app.ActivityManager.TaskDescription, @NonNull android.graphics.Bitmap);
+    method public void appNotResponding(@NonNull String);
     method public boolean clearApplicationUserData();
     method public void clearWatchHeapLimit();
     method @RequiresPermission(android.Manifest.permission.DUMP) public void dumpPackageState(java.io.FileDescriptor, String);
@@ -51681,6 +51682,7 @@
     method public boolean isScrollContainer();
     method public boolean isScrollbarFadingEnabled();
     method @android.view.ViewDebug.ExportedProperty public boolean isSelected();
+    method public final boolean isShowingLayoutBounds();
     method public boolean isShown();
     method @android.view.ViewDebug.ExportedProperty public boolean isSoundEffectsEnabled();
     method public final boolean isTemporarilyDetached();
diff --git a/api/removed.txt b/api/removed.txt
index 8b30d0a..fb6d576 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -435,15 +435,6 @@
     field @Deprecated public static final String TIMESTAMP = "timestamp";
   }
 
-  public final class MediaStore {
-    method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
-    method @Deprecated public static boolean getIncludePending(@NonNull android.net.Uri);
-    method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
-    method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
-    method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
-    method @Deprecated public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
-  }
-
   public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns {
     field public static final String ALBUM = "album";
     field public static final String ARTIST = "artist";
diff --git a/api/system-current.txt b/api/system-current.txt
index a551568..c0f8ceb 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1934,10 +1934,12 @@
   }
 
   public class DataLoaderParams {
-    ctor public DataLoaderParams(@NonNull String, @NonNull String, @Nullable java.util.Map<java.lang.String,android.os.ParcelFileDescriptor>);
+    method @NonNull public static final android.content.pm.DataLoaderParams forIncremental(@NonNull android.content.ComponentName, @NonNull String, @Nullable java.util.Map<java.lang.String,android.os.ParcelFileDescriptor>);
+    method @NonNull public static final android.content.pm.DataLoaderParams forStreaming(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull public final String getArguments();
+    method @NonNull public final android.content.ComponentName getComponentName();
     method @NonNull public final java.util.Map<java.lang.String,android.os.ParcelFileDescriptor> getDynamicArgs();
-    method @NonNull public final String getPackageName();
-    method @NonNull public final String getStaticArgs();
+    method @NonNull public final int getType();
   }
 
   public final class InstantAppInfo implements android.os.Parcelable {
@@ -2050,11 +2052,11 @@
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
     method @Deprecated public void setAllowDowngrade(boolean);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
     method public void setDontKillApp(boolean);
     method public void setEnableRollback(boolean);
     method public void setEnableRollback(boolean, int);
     method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
-    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setIncrementalParams(@NonNull android.content.pm.DataLoaderParams);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
@@ -5392,11 +5394,15 @@
     ctor public EasyConnectStatusCallback();
     method public abstract void onConfiguratorSuccess(int);
     method public abstract void onEnrolleeSuccess(int);
-    method public abstract void onFailure(int);
+    method public void onFailure(int);
+    method public void onFailure(int, @Nullable String, @NonNull android.util.SparseArray<int[]>, @NonNull int[]);
     method public abstract void onProgress(int);
     field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
     field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+    field public static final int EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK = -10; // 0xfffffff6
     field public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+    field public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION = -11; // 0xfffffff5
+    field public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12; // 0xfffffff4
     field public static final int EASY_CONNECT_EVENT_FAILURE_GENERIC = -7; // 0xfffffff9
     field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
     field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
@@ -5404,7 +5410,10 @@
     field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
     field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
     field public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+    field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3; // 0x3
+    field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2; // 0x2
     field public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+    field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1; // 0x1
     field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
   }
 
@@ -8972,6 +8981,34 @@
     field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService";
   }
 
+  public abstract class CellIdentity implements android.os.Parcelable {
+    method @NonNull public abstract android.telephony.CellLocation asCellLocation();
+  }
+
+  public final class CellIdentityCdma extends android.telephony.CellIdentity {
+    method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation();
+  }
+
+  public final class CellIdentityGsm extends android.telephony.CellIdentity {
+    method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+  }
+
+  public final class CellIdentityLte extends android.telephony.CellIdentity {
+    method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+  }
+
+  public final class CellIdentityNr extends android.telephony.CellIdentity {
+    method @NonNull public android.telephony.CellLocation asCellLocation();
+  }
+
+  public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
+    method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+  }
+
+  public final class CellIdentityWcdma extends android.telephony.CellIdentity {
+    method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+  }
+
   public final class DataFailCause {
     field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab
     field public static final int ACCESS_BLOCK = 2087; // 0x827
@@ -9571,6 +9608,7 @@
   }
 
   public final class PreciseCallState implements android.os.Parcelable {
+    ctor public PreciseCallState(int, int, int, int, int);
     method public int describeContents();
     method public int getBackgroundCallState();
     method public int getForegroundCallState();
diff --git a/api/test-current.txt b/api/test-current.txt
index 503941c..08a2160 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4359,6 +4359,7 @@
     method public void setAutofilled(boolean);
     method public final void setFocusedInCluster();
     method public void setIsRootNamespace(boolean);
+    method public final void setShowingLayoutBounds(boolean);
   }
 
   public class ViewConfiguration {
diff --git a/core/java/android/annotation/RequiresPermission.java b/core/java/android/annotation/RequiresPermission.java
index 59d419f..e5c0654 100644
--- a/core/java/android/annotation/RequiresPermission.java
+++ b/core/java/android/annotation/RequiresPermission.java
@@ -15,8 +15,6 @@
  */
 package android.annotation;
 
-import android.content.Intent;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
@@ -57,7 +55,7 @@
  * <p>
  * When specified on a parameter, the annotation indicates that the method requires
  * a permission which depends on the value of the parameter. For example, consider
- * {@link android.app.Activity#startActivity(Intent)}:
+ * {@link android.app.Activity#startActivity(android.content.Intent)}:
  * <pre>{@code
  *   public void startActivity(@RequiresPermission Intent intent) { ... }
  * }</pre>
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 68bdfae..3f9f7fb 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4547,4 +4547,17 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Method for the app to tell system that it's wedged and would like to trigger an ANR.
+     *
+     * @param reason The description of that what happened
+     */
+    public void appNotResponding(@NonNull final String reason) {
+        try {
+            getService().appNotResponding(reason);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 112bd30..e8494c4 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -583,4 +583,9 @@
      * unlockProgressListener can be null if monitoring progress is not necessary.
      */
     boolean startUserInForegroundWithListener(int userid, IProgressListener unlockProgressListener);
+
+    /**
+     * Method for the app to tell system that it's wedged and would like to trigger an ANR.
+     */
+    void appNotResponding(String reason);
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c5a147a..7967708 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -11050,6 +11050,7 @@
                 case ACTION_MEDIA_SCANNER_FINISHED:
                 case ACTION_MEDIA_SCANNER_SCAN_FILE:
                 case ACTION_PACKAGE_NEEDS_VERIFICATION:
+                case ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION:
                 case ACTION_PACKAGE_VERIFIED:
                 case ACTION_PACKAGE_ENABLE_ROLLBACK:
                     // Ignore legacy actions
diff --git a/core/java/android/content/pm/DataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java
index af4b99a..60d7bb3 100644
--- a/core/java/android/content/pm/DataLoaderParams.java
+++ b/core/java/android/content/pm/DataLoaderParams.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.content.ComponentName;
 import android.os.ParcelFileDescriptor;
 
 import java.util.Arrays;
@@ -26,7 +27,7 @@
 import java.util.stream.Collectors;
 
 /**
- * This class represents the parameters used to configure an Incremental Data Loader.
+ * This class represents the parameters used to configure a Data Loader.
  *
  * WARNING: This is a system API to aid internal development.
  * Use at your own risk. It will change or be removed without warning.
@@ -34,13 +35,41 @@
  */
 @SystemApi
 public class DataLoaderParams {
-    @NonNull private final DataLoaderParamsParcel mData;
+    @NonNull
+    private final DataLoaderParamsParcel mData;
 
-    public DataLoaderParams(@NonNull String url, @NonNull String packageName,
+    /**
+     * Creates and populates set of Data Loader parameters for Streaming installation.
+     *
+     * @param componentName Data Loader component supporting Streaming installation.
+     * @param arguments free form installation arguments
+     */
+    public static final @NonNull DataLoaderParams forStreaming(@NonNull ComponentName componentName,
+            @NonNull String arguments) {
+        return new DataLoaderParams(DataLoaderType.STREAMING, componentName, arguments, null);
+    }
+
+    /**
+     * Creates and populates set of Data Loader parameters for Incremental installation.
+     *
+     * @param componentName Data Loader component supporting Incremental installation.
+     * @param arguments free form installation arguments
+     * @param namedFds TODO(b/146080380) remove
+     */
+    public static final @NonNull DataLoaderParams forIncremental(
+            @NonNull ComponentName componentName, @NonNull String arguments,
             @Nullable Map<String, ParcelFileDescriptor> namedFds) {
+        return new DataLoaderParams(DataLoaderType.INCREMENTAL, componentName, arguments, namedFds);
+    }
+
+    /** @hide */
+    public DataLoaderParams(@NonNull @DataLoaderType int type, @NonNull ComponentName componentName,
+            @NonNull String arguments, @Nullable Map<String, ParcelFileDescriptor> namedFds) {
         DataLoaderParamsParcel data = new DataLoaderParamsParcel();
-        data.staticArgs = url;
-        data.packageName = packageName;
+        data.type = type;
+        data.packageName = componentName.getPackageName();
+        data.className = componentName.getClassName();
+        data.arguments = arguments;
         if (namedFds == null || namedFds.isEmpty()) {
             data.dynamicArgs = new NamedParcelFileDescriptor[0];
         } else {
@@ -56,39 +85,42 @@
         mData = data;
     }
 
-    /**
-     * @hide
-     */
-    public DataLoaderParams(@NonNull DataLoaderParamsParcel data) {
+    /** @hide */
+    DataLoaderParams(@NonNull DataLoaderParamsParcel data) {
         mData = data;
     }
 
-    /**
-     * @return static server's URL
-     */
-    public final @NonNull String getStaticArgs() {
-        return mData.staticArgs;
-    }
-
-    /**
-     * @return data loader's package name
-     */
-    public final @NonNull String getPackageName() {
-        return mData.packageName;
-    }
-
-    /**
-     * @hide
-     */
+    /** @hide */
     public final @NonNull DataLoaderParamsParcel getData() {
         return mData;
     }
 
     /**
-     * @return data loader's dynamic arguments such as file descriptors
+     * @return data loader type
+     */
+    public final @NonNull @DataLoaderType int getType() {
+        return mData.type;
+    }
+
+    /**
+     * @return data loader's component name
+     */
+    public final @NonNull ComponentName getComponentName() {
+        return new ComponentName(mData.packageName, mData.className);
+    }
+
+    /**
+     * @return data loader's arguments
+     */
+    public final @NonNull String getArguments() {
+        return mData.arguments;
+    }
+
+    /**
+     * @return data loader's dynamic arguments such as file descriptors TODO: remove
      */
     public final @NonNull Map<String, ParcelFileDescriptor> getDynamicArgs() {
         return Arrays.stream(mData.dynamicArgs).collect(
-            Collectors.toMap(p->p.name, p->p.fd));
+                Collectors.toMap(p -> p.name, p -> p.fd));
     }
 }
diff --git a/core/java/android/content/pm/DataLoaderParamsParcel.aidl b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
index 3316398..e05843b 100644
--- a/core/java/android/content/pm/DataLoaderParamsParcel.aidl
+++ b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.content.pm.DataLoaderType;
 import android.content.pm.NamedParcelFileDescriptor;
 
 /**
@@ -23,7 +24,9 @@
  * @hide
  */
 parcelable DataLoaderParamsParcel {
+    DataLoaderType type;
     @utf8InCpp String packageName;
-    @utf8InCpp String staticArgs;
+    @utf8InCpp String className;
+    @utf8InCpp String arguments;
     NamedParcelFileDescriptor[] dynamicArgs;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java b/core/java/android/content/pm/DataLoaderType.aidl
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java
copy to core/java/android/content/pm/DataLoaderType.aidl
index bc6b83b..7d726f5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java
+++ b/core/java/android/content/pm/DataLoaderType.aidl
@@ -14,17 +14,24 @@
  * limitations under the License.
  */
 
-package com.android.systemui.dagger.qualifiers;
+package android.content.pm;
 
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface BgHandler {
+/**
+ * Types of Data Loader for an installation session.
+ * @hide
+ */
+@Backing(type="int")
+enum DataLoaderType {
+    /**
+    * Default value, legacy installation.
+    */
+    NONE = 0,
+    /**
+     * Streaming installation using data loader.
+     */
+    STREAMING = 1,
+    /**
+     * Streaming installation using Incremental FileSystem.
+     */
+    INCREMENTAL = 2,
 }
diff --git a/core/java/android/content/pm/IDataLoader.aidl b/core/java/android/content/pm/IDataLoader.aidl
index c65bd6a..b5baa93 100644
--- a/core/java/android/content/pm/IDataLoader.aidl
+++ b/core/java/android/content/pm/IDataLoader.aidl
@@ -27,7 +27,9 @@
  */
 oneway interface IDataLoader {
    void create(int id, in Bundle params, IDataLoaderStatusListener listener);
-   void start(in List<InstallationFile> fileInfos);
+   void start();
    void stop();
    void destroy();
+
+   void prepareImage(in List<InstallationFile> addedFiles, in List<String> removedFiles);
 }
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index a60d6ee..5011faa 100644
--- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -22,13 +22,18 @@
  */
 oneway interface IDataLoaderStatusListener {
     /** Data loader status */
-    const int DATA_LOADER_READY = 0;
-    const int DATA_LOADER_NOT_READY = 1;
-    const int DATA_LOADER_RUNNING = 2;
+    const int DATA_LOADER_CREATED = 0;
+    const int DATA_LOADER_DESTROYED = 1;
+
+    const int DATA_LOADER_STARTED = 2;
     const int DATA_LOADER_STOPPED = 3;
-    const int DATA_LOADER_SLOW_CONNECTION = 4;
-    const int DATA_LOADER_NO_CONNECTION = 5;
-    const int DATA_LOADER_CONNECTION_OK = 6;
+
+    const int DATA_LOADER_IMAGE_READY = 4;
+    const int DATA_LOADER_IMAGE_NOT_READY = 5;
+
+    const int DATA_LOADER_SLOW_CONNECTION = 6;
+    const int DATA_LOADER_NO_CONNECTION = 7;
+    const int DATA_LOADER_CONNECTION_OK = 8;
 
     /** Data loader status callback */
     void onStatusChanged(in int dataLoaderId, in int status);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3d6d849..e4a0bc0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1461,10 +1461,7 @@
         /** {@hide} */
         public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
         /** {@hide} */
-        public DataLoaderParams incrementalParams;
-        /** TODO(b/146080380): add a class name to make it fully compatible with ComponentName.
-         * {@hide} */
-        public String dataLoaderPackageName;
+        public DataLoaderParams dataLoaderParams;
         /** {@hide} */
         public int rollbackDataPolicy = PackageManager.RollbackDataPolicy.RESTORE;
 
@@ -1503,10 +1500,8 @@
             DataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
                     DataLoaderParamsParcel.class.getClassLoader());
             if (dataLoaderParamsParcel != null) {
-                incrementalParams = new DataLoaderParams(
-                        dataLoaderParamsParcel);
+                dataLoaderParams = new DataLoaderParams(dataLoaderParamsParcel);
             }
-            dataLoaderPackageName = source.readString();
             rollbackDataPolicy = source.readInt();
         }
 
@@ -1531,8 +1526,7 @@
             ret.isMultiPackage = isMultiPackage;
             ret.isStaged = isStaged;
             ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
-            ret.incrementalParams = incrementalParams;
-            ret.dataLoaderPackageName = dataLoaderPackageName;
+            ret.dataLoaderParams = dataLoaderParams;
             ret.rollbackDataPolicy = rollbackDataPolicy;
             return ret;
         }
@@ -1893,29 +1887,18 @@
         }
 
         /**
-         * Set Incremental data loader params.
+         * Set the data loader params for the session.
+         * This also switches installation into data provider mode and disallow direct writes into
+         * staging folder.
+         *
          * WARNING: This is a system API to aid internal development.
          * Use at your own risk. It will change or be removed without warning.
          * {@hide}
          */
         @SystemApi
         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
-        public void setIncrementalParams(@NonNull DataLoaderParams incrementalParams) {
-            this.incrementalParams = incrementalParams;
-        }
-
-        /**
-         * Set the data provider params for the session.
-         * This also switches installation into callback mode and disallow direct writes into
-         * staging folder.
-         * TODO(b/146080380): unify dataprovider params with Incremental.
-         *
-         * @param dataLoaderPackageName name of the dataLoader package
-         * {@hide}
-         */
-        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
-        public void setDataLoaderPackageName(String dataLoaderPackageName) {
-            this.dataLoaderPackageName = dataLoaderPackageName;
+        public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
+            this.dataLoaderParams = dataLoaderParams;
         }
 
         /** {@hide} */
@@ -1938,7 +1921,7 @@
             pw.printPair("isMultiPackage", isMultiPackage);
             pw.printPair("isStaged", isStaged);
             pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
-            pw.printPair("dataLoaderPackageName", dataLoaderPackageName);
+            pw.printPair("dataLoaderParams", dataLoaderParams);
             pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
             pw.println();
         }
@@ -1969,12 +1952,11 @@
             dest.writeBoolean(isMultiPackage);
             dest.writeBoolean(isStaged);
             dest.writeLong(requiredInstalledVersionCode);
-            if (incrementalParams != null) {
-                dest.writeParcelable(incrementalParams.getData(), flags);
+            if (dataLoaderParams != null) {
+                dest.writeParcelable(dataLoaderParams.getData(), flags);
             } else {
                 dest.writeParcelable(null, flags);
             }
-            dest.writeString(dataLoaderPackageName);
             dest.writeInt(rollbackDataPolicy);
         }
 
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index fb94fc9..2138d553 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -87,8 +87,8 @@
         mPackageName = packageName;
         mStageDir = stageDir;
         mIncrementalManager = incrementalManager;
-        if (dataLoaderParams.getPackageName().equals("local")) {
-            final String incrementalPath = dataLoaderParams.getStaticArgs();
+        if (dataLoaderParams.getComponentName().getPackageName().equals("local")) {
+            final String incrementalPath = dataLoaderParams.getArguments();
             mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
             mDefaultDir = incrementalPath;
             return;
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index 54a4fa6..75f252e 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -16,7 +16,6 @@
 
 package android.service.dataloader;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -27,19 +26,16 @@
 import android.content.pm.FileSystemControlParcel;
 import android.content.pm.IDataLoader;
 import android.content.pm.IDataLoaderStatusListener;
-import android.content.pm.IPackageInstallerSessionFileSystemConnector;
 import android.content.pm.InstallationFile;
 import android.content.pm.NamedParcelFileDescriptor;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
 import android.util.ExceptionUtils;
 import android.util.Slog;
 
 import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -55,88 +51,35 @@
  */
 @SystemApi
 public abstract class DataLoaderService extends Service {
-    private static final String TAG = "IncrementalDataLoaderService";
+    private static final String TAG = "DataLoaderService";
     private final DataLoaderBinderService mBinder = new DataLoaderBinderService();
 
-    /** @hide */
-    public static final int DATA_LOADER_READY =
-            IDataLoaderStatusListener.DATA_LOADER_READY;
-    /** @hide */
-    public static final int DATA_LOADER_NOT_READY =
-            IDataLoaderStatusListener.DATA_LOADER_NOT_READY;
-    /** @hide */
-    public static final int DATA_LOADER_RUNNING =
-            IDataLoaderStatusListener.DATA_LOADER_RUNNING;
-    /** @hide */
-    public static final int DATA_LOADER_STOPPED =
-            IDataLoaderStatusListener.DATA_LOADER_STOPPED;
-    /** @hide */
-    public static final int DATA_LOADER_SLOW_CONNECTION =
-            IDataLoaderStatusListener.DATA_LOADER_SLOW_CONNECTION;
-    /** @hide */
-    public static final int DATA_LOADER_NO_CONNECTION =
-            IDataLoaderStatusListener.DATA_LOADER_NO_CONNECTION;
-    /** @hide */
-    public static final int DATA_LOADER_CONNECTION_OK =
-            IDataLoaderStatusListener.DATA_LOADER_CONNECTION_OK;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"DATA_LOADER_"}, value = {
-            DATA_LOADER_READY,
-            DATA_LOADER_NOT_READY,
-            DATA_LOADER_RUNNING,
-            DATA_LOADER_STOPPED,
-            DATA_LOADER_SLOW_CONNECTION,
-            DATA_LOADER_NO_CONNECTION,
-            DATA_LOADER_CONNECTION_OK
-    })
-    public @interface DataLoaderStatus {
-    }
-
     /**
-     * Managed DataLoader interface. Each instance corresponds to a single Incremental File System
-     * instance.
+     * Managed DataLoader interface. Each instance corresponds to a single installation session.
      * @hide
      */
-    public abstract static class DataLoader {
+    public interface DataLoader {
         /**
-         * A virtual constructor used to do simple initialization. Not ready to serve any data yet.
-         * All heavy-lifting has to be done in onStart.
+         * A virtual constructor.
          *
-         * @param params    Data loader configuration parameters.
-         * @param connector IncFS API wrapper.
-         * @param listener  Used for reporting internal state to IncrementalService.
+         * @param dataLoaderParams parameters set in the installation session
+         * @param connector FS API wrapper
          * @return True if initialization of a Data Loader was successful. False will be reported to
-         * IncrementalService and can cause an unmount of an IFS instance.
+         * PackageManager and fail the installation
          */
-        public abstract boolean onCreate(@NonNull DataLoaderParams params,
-                @NonNull FileSystemConnector connector,
-                @NonNull StatusListener listener);
+        boolean onCreate(@NonNull DataLoaderParams dataLoaderParams,
+                @NonNull FileSystemConnector connector);
 
         /**
-         * Start the data loader. After this method returns data loader is considered to be ready to
-         * receive callbacks from IFS, supply data via connector and send status updates via
-         * callbacks.
+         * Prepare installation image. After this method succeeds installer will validate the files
+         * and continue installation.
          *
-         * @return True if Data Loader was able to start. False will be reported to
-         * IncrementalService and can cause an unmount of an IFS instance.
+         * @param addedFiles   list of files created in this installation session.
+         * @param removedFiles list of files removed in this installation session.
+         * @return false if unable to create and populate all addedFiles.
          */
-        public abstract boolean onStart();
-
-        /**
-         * Stop the data loader. Use to stop any additional threads and free up resources. Data
-         * loader is not longer responsible for supplying data. Start/Stop pair can be called
-         * multiple times e.g. if IFS detects corruption and data needs to be re-loaded.
-         */
-        public abstract void onStop();
-
-        /**
-         * Virtual destructor. Use to cleanup all internal state. After this method returns, the
-         * data loader can no longer use connector or callbacks. For any additional operations with
-         * this instance of IFS a new DataLoader will be created using createDataLoader method.
-         */
-        public abstract void onDestroy();
+        boolean onPrepareImage(Collection<InstallationFile> addedFiles,
+                Collection<String> removedFiles);
     }
 
     /**
@@ -145,7 +88,9 @@
      * @return An instance of a DataLoader.
      * @hide
      */
-    public abstract @Nullable DataLoader onCreateDataLoader();
+    public @Nullable DataLoader onCreateDataLoader() {
+        return null;
+    }
 
     /**
      * @hide
@@ -160,148 +105,125 @@
         @Override
         public void create(int id, @NonNull Bundle options,
                 @NonNull IDataLoaderStatusListener listener)
-                    throws IllegalArgumentException, RuntimeException {
+                throws IllegalArgumentException, RuntimeException {
             mId = id;
-            final DataLoaderParamsParcel params =  options.getParcelable("params");
+            final DataLoaderParamsParcel params = options.getParcelable("params");
             if (params == null) {
-                throw new IllegalArgumentException("Must specify Incremental data loader params");
+                throw new IllegalArgumentException("Must specify data loader params");
             }
-            final FileSystemControlParcel control =
-                    options.getParcelable("control");
+            final FileSystemControlParcel control = options.getParcelable("control");
             if (control == null) {
-                throw new IllegalArgumentException("Must specify Incremental control parcel");
+                throw new IllegalArgumentException("Must specify control parcel");
             }
-            mStatusListener = listener;
             try {
                 if (!nativeCreateDataLoader(id, control, params, listener)) {
                     Slog.e(TAG, "Failed to create native loader for " + mId);
                 }
             } catch (Exception ex) {
+                Slog.e(TAG, "Failed to create native loader for " + mId, ex);
                 destroy();
                 throw new RuntimeException(ex);
             } finally {
                 // Closing FDs.
-                if (control.incremental.cmd != null) {
-                    try {
-                        control.incremental.cmd.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e);
+                if (control.incremental != null) {
+                    if (control.incremental.cmd != null) {
+                        try {
+                            control.incremental.cmd.close();
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e);
+                        }
+                    }
+                    if (control.incremental.log != null) {
+                        try {
+                            control.incremental.log.close();
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e);
+                        }
                     }
                 }
-                if (control.incremental.log != null) {
-                    try {
-                        control.incremental.log.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e);
-                    }
-                }
-                NamedParcelFileDescriptor[] fds = params.dynamicArgs;
-                for (NamedParcelFileDescriptor nfd : fds) {
-                    try {
-                        nfd.fd.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG,
-                                "Failed to close DynamicArgs parcel file descriptor " + e);
+                if (params.dynamicArgs != null) {
+                    NamedParcelFileDescriptor[] fds = params.dynamicArgs;
+                    for (NamedParcelFileDescriptor nfd : fds) {
+                        try {
+                            nfd.fd.close();
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Failed to close DynamicArgs parcel file descriptor " + e);
+                        }
                     }
                 }
             }
         }
 
         @Override
-        public void start(List<InstallationFile> fileInfos) {
+        public void start() {
             if (!nativeStartDataLoader(mId)) {
-                Slog.e(TAG, "Failed to start loader: loader not found for " + mId);
+                Slog.e(TAG, "Failed to start loader: " + mId);
             }
         }
 
         @Override
         public void stop() {
             if (!nativeStopDataLoader(mId)) {
-                Slog.w(TAG, "Failed to stop loader: loader not found for " + mId);
+                Slog.w(TAG, "Failed to stop loader: " + mId);
             }
         }
 
         @Override
         public void destroy() {
             if (!nativeDestroyDataLoader(mId)) {
-                Slog.w(TAG, "Failed to destroy loader: loader not found for " + mId);
+                Slog.w(TAG, "Failed to destroy loader: " + mId);
+            }
+        }
+
+        @Override
+        public void prepareImage(List<InstallationFile> addedFiles, List<String> removedFiles) {
+            if (!nativePrepareImage(mId, addedFiles, removedFiles)) {
+                Slog.w(TAG, "Failed to destroy loader: " + mId);
             }
         }
     }
 
     /**
-     *
      * Used by the DataLoaderService implementations.
      *
      * @hide
      */
     public static final class FileSystemConnector {
         /**
-         * Creates a wrapper for an installation session connector.
+         * Create a wrapper for a native instance.
+         *
          * @hide
          */
-        FileSystemConnector(IPackageInstallerSessionFileSystemConnector connector) {
-            mConnector = connector;
+        FileSystemConnector(long nativeInstance) {
+            mNativeInstance = nativeInstance;
         }
 
         /**
          * Write data to an installation file from an arbitrary FD.
          *
-         * @param name name of file previously added to the installation session.
-         * @param offsetBytes offset into the file to begin writing at, or 0 to
-         *            start at the beginning of the file.
-         * @param lengthBytes total size of the file being written, used to
-         *            preallocate the underlying disk space, or -1 if unknown.
-         *            The system may clear various caches as needed to allocate
-         *            this space.
-         * @param incomingFd FD to read bytes from.
-         * @throws IOException if trouble opening the file for writing, such as
-         *             lack of disk space or unavailable media.
+         * @param name        name of file previously added to the installation session.
+         * @param offsetBytes offset into the file to begin writing at, or 0 to start at the
+         *                    beginning of the file.
+         * @param lengthBytes total size of the file being written, used to preallocate the
+         *                    underlying disk space, or -1 if unknown. The system may clear various
+         *                    caches as needed to allocate this space.
+         * @param incomingFd  FD to read bytes from.
+         * @throws IOException if trouble opening the file for writing, such as lack of disk space
+         *                     or unavailable media.
          */
         public void writeData(String name, long offsetBytes, long lengthBytes,
                 ParcelFileDescriptor incomingFd) throws IOException {
             try {
-                mConnector.writeData(name, offsetBytes, lengthBytes, incomingFd);
+                nativeWriteData(mNativeInstance, name, offsetBytes, lengthBytes, incomingFd);
             } catch (RuntimeException e) {
                 ExceptionUtils.maybeUnwrapIOException(e);
                 throw e;
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
             }
         }
 
-        private final IPackageInstallerSessionFileSystemConnector mConnector;
-    }
-
-    /**
-     * Wrapper for native reporting DataLoader statuses.
-     * @hide
-     */
-    public static final class StatusListener {
-        /**
-         * Creates a wrapper for a native instance.
-         * @hide
-         */
-        StatusListener(long nativeInstance) {
-            mNativeInstance = nativeInstance;
-        }
-
-        /**
-         * Report the status of DataLoader. Used for system-wide notifications e.g., disabling
-         * applications which rely on this data loader to function properly.
-         *
-         * @param status status to report.
-         * @return True if status was reported successfully.
-         */
-        public boolean onStatusChanged(@DataLoaderStatus int status) {
-            return nativeReportStatus(mNativeInstance, status);
-        }
-
         private final long mNativeInstance;
     }
 
-    private IDataLoaderStatusListener mStatusListener = null;
-
     /* Native methods */
     private native boolean nativeCreateDataLoader(int storageId,
             @NonNull FileSystemControlParcel control,
@@ -314,5 +236,10 @@
 
     private native boolean nativeDestroyDataLoader(int storageId);
 
-    private static native boolean nativeReportStatus(long nativeInstance, int status);
+    private native boolean nativePrepareImage(int storageId,
+            Collection<InstallationFile> addedFiles, Collection<String> removedFiles);
+
+    private static native void nativeWriteData(long nativeInstance, String name, long offsetBytes,
+            long lengthBytes, ParcelFileDescriptor incomingFd);
+
 }
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 51a9c86..e5f2c3a 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -24,7 +24,6 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
@@ -993,8 +992,11 @@
                     () -> mExecutor.execute(() -> psl.onCallForwardingIndicatorChanged(cfi)));
         }
 
-        public void onCellLocationChanged(Bundle bundle) {
-            CellLocation location = CellLocation.newFromBundle(bundle);
+        public void onCellLocationChanged(CellIdentity cellIdentity) {
+            // There is no system/public API to create an CellIdentity in system server,
+            // so the server pass a null to indicate an empty initial location.
+            CellLocation location =
+                    cellIdentity == null ? CellLocation.getEmpty() : cellIdentity.asCellLocation();
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index f574160..1b2feda 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -22,7 +22,6 @@
 import android.annotation.TestApi;
 import android.content.Context;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.Annotation.CallState;
@@ -633,10 +632,14 @@
     }
 
     /**
-     * TODO change from bundle to CellLocation?
+     * Notify {@link android.telephony.CellLocation} changed.
+     *
+     * <p>To be compatible with {@link TelephonyRegistry}, use {@link CellIdentity} which is
+     * parcelable, and convert to CellLocation in client code.
+     *
      * @hide
      */
-    public void notifyCellLocation(int subId, Bundle cellLocation) {
+    public void notifyCellLocation(int subId, CellIdentity cellLocation) {
         try {
             sRegistry.notifyCellLocationForSubscriber(subId, cellLocation);
         } catch (RemoteException ex) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1a5b3e5..0db80e2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6162,10 +6162,27 @@
         mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));
     }
 
-    final boolean debugDraw() {
+    /**
+     * Returns {@code true} when the View is attached and the system developer setting to show
+     * the layout bounds is enabled or {@code false} otherwise.
+     */
+    public final boolean isShowingLayoutBounds() {
         return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
     }
 
+    /**
+     * Used to test isShowingLayoutBounds(). This sets the local value used
+     * by that function. This method does nothing if the layout isn't attached.
+     *
+     * @hide
+     */
+    @TestApi
+    public final void setShowingLayoutBounds(boolean debugLayout) {
+        if (mAttachInfo != null) {
+            mAttachInfo.mDebugLayout = debugLayout;
+        }
+    }
+
     private static SparseArray<String> getAttributeMap() {
         if (mAttributeMap == null) {
             mAttributeMap = new SparseArray<>();
@@ -20881,7 +20898,7 @@
                         if (mOverlay != null && !mOverlay.isEmpty()) {
                             mOverlay.getOverlayView().draw(canvas);
                         }
-                        if (debugDraw()) {
+                        if (isShowingLayoutBounds()) {
                             debugDrawFocus(canvas);
                         }
                     } else {
@@ -22026,7 +22043,7 @@
             // Step 7, draw the default focus highlight
             drawDefaultFocusHighlight(canvas);
 
-            if (debugDraw()) {
+            if (isShowingLayoutBounds()) {
                 debugDrawFocus(canvas);
             }
 
@@ -22201,7 +22218,7 @@
         // Step 6, draw decorations (foreground, scrollbars)
         onDrawForeground(canvas);
 
-        if (debugDraw()) {
+        if (isShowingLayoutBounds()) {
             debugDrawFocus(canvas);
         }
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 21e9e31..5fb7177 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -681,7 +681,7 @@
 
     private void initViewGroup() {
         // ViewGroup doesn't draw by default
-        if (!debugDraw()) {
+        if (!isShowingLayoutBounds()) {
             setFlags(WILL_NOT_DRAW, DRAW_MASK);
         }
         mGroupFlags |= FLAG_CLIP_CHILDREN;
@@ -4156,7 +4156,7 @@
         }
         if (usingRenderNodeProperties) canvas.insertInorderBarrier();
 
-        if (debugDraw()) {
+        if (isShowingLayoutBounds()) {
             onDebugDraw(canvas);
         }
 
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 33b2113..c610ac4 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -45,12 +45,14 @@
     public static final String EXTRA_SUSPENDING_PACKAGE =
             PACKAGE_NAME + ".extra.SUSPENDING_PACKAGE";
     public static final String EXTRA_DIALOG_INFO = PACKAGE_NAME + ".extra.DIALOG_INFO";
+    public static final String EXTRA_ACTIVITY_OPTIONS = PACKAGE_NAME + ".extra.ACTIVITY_OPTIONS";
 
     private Intent mMoreDetailsIntent;
     private int mUserId;
     private PackageManager mPm;
     private Resources mSuspendingAppResources;
     private SuspendDialogInfo mSuppliedDialogInfo;
+    private Bundle mOptions;
 
     private CharSequence getAppLabel(String packageName) {
         try {
@@ -143,6 +145,7 @@
         getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
 
         final Intent intent = getIntent();
+        mOptions = intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS);
         mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
         if (mUserId < 0) {
             Slog.wtf(TAG, "Invalid user: " + mUserId);
@@ -178,20 +181,22 @@
     public void onClick(DialogInterface dialog, int which) {
         switch (which) {
             case AlertDialog.BUTTON_NEUTRAL:
-                startActivityAsUser(mMoreDetailsIntent, UserHandle.of(mUserId));
-                Slog.i(TAG, "Started more details activity");
+                startActivityAsUser(mMoreDetailsIntent, mOptions, UserHandle.of(mUserId));
+                Slog.i(TAG, "Started activity: " + mMoreDetailsIntent.getAction()
+                        + " in user " + mUserId);
                 break;
         }
         finish();
     }
 
     public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
-            String suspendingPackage, SuspendDialogInfo dialogInfo, int userId) {
+            String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options, int userId) {
         return new Intent()
                 .setClassName("android", SuspendedAppActivity.class.getName())
                 .putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
                 .putExtra(EXTRA_DIALOG_INFO, dialogInfo)
                 .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
+                .putExtra(EXTRA_ACTIVITY_OPTIONS, options)
                 .putExtra(Intent.EXTRA_USER_ID, userId)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                         | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index c390a51..2248b88 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -316,7 +316,9 @@
      * @param appDataDir null-ok  The data directory of the app.
      * @param isTopApp  True if the process is for top (high priority) application.
      * @param pkgDataInfoList A list that stores related packages and its app data
-     * info: volume uuid and inode.
+     * volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
+     * app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
+     * app_b_ce_inode, ...];
      */
     private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName,
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index cb67309..6c7e3dc 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -16,8 +16,8 @@
 
 package com.android.internal.telephony;
 
-import android.os.Bundle;
 import android.telephony.CallAttributes;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneCapability;
@@ -37,8 +37,8 @@
     void onMessageWaitingIndicatorChanged(boolean mwi);
     void onCallForwardingIndicatorChanged(boolean cfi);
 
-    // we use bundle here instead of CellLocation so it can get the right subclass
-    void onCellLocationChanged(in Bundle location);
+    // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
+    void onCellLocationChanged(in CellIdentity location);
     void onCallStateChanged(int state, String incomingNumber);
     void onDataConnectionStateChanged(int state, int networkType);
     void onDataActivity(int direction);
@@ -63,4 +63,3 @@
     void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause);
     void onImsCallDisconnectCauseChanged(in ImsReasonInfo imsReasonInfo);
 }
-
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index f954679..4e40503 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -19,8 +19,8 @@
 import android.content.Intent;
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
-import android.os.Bundle;
 import android.telephony.CallQuality;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.PhoneCapability;
@@ -66,9 +66,9 @@
             int phoneId, int subId, String apnType, in PreciseDataConnectionState preciseState);
     @UnsupportedAppUsage
     void notifyDataConnectionFailed(String apnType);
-    @UnsupportedAppUsage(maxTargetSdk = 28)
-    void notifyCellLocation(in Bundle cellLocation);
-    void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation);
+    // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
+    void notifyCellLocation(in CellIdentity cellLocation);
+    void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
     @UnsupportedAppUsage
     void notifyCellInfo(in List<CellInfo> cellInfo);
     void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
diff --git a/core/jni/android_service_DataLoaderService.cpp b/core/jni/android_service_DataLoaderService.cpp
index 381b386..a62d127 100644
--- a/core/jni/android_service_DataLoaderService.cpp
+++ b/core/jni/android_service_DataLoaderService.cpp
@@ -51,13 +51,19 @@
 }
 
 
-static jboolean nativeReportStatus(JNIEnv* env,
-                                   jobject clazz,
-                                   jlong self,
-                                   jint status) {
-    auto listener = (DataLoaderStatusListenerPtr)self;
-    return DataLoader_StatusListener_reportStatus(listener,
-                     (DataLoaderStatus)status);
+static jboolean nativePrepareImage(JNIEnv* env, jobject thiz, jint storageId, jobject addedFiles, jobject removedFiles) {
+    return DataLoaderService_OnPrepareImage(storageId, addedFiles, removedFiles);
+}
+
+static void nativeWriteData(JNIEnv* env,
+                            jobject clazz,
+                            jlong self,
+                            jstring name,
+                            jlong offsetBytes,
+                            jlong lengthBytes,
+                            jobject incomingFd) {
+    auto connector = (DataLoaderFilesystemConnectorPtr)self;
+    return DataLoader_FilesystemConnector_writeData(connector, name, offsetBytes, lengthBytes, incomingFd);
 }
 
 static const JNINativeMethod dlc_method_table[] = {
@@ -69,7 +75,8 @@
         {"nativeStartDataLoader", "(I)Z", (void*)nativeStartDataLoader},
         {"nativeStopDataLoader", "(I)Z", (void*)nativeStopDataLoader},
         {"nativeDestroyDataLoader", "(I)Z", (void*)nativeDestroyDataLoader},
-        {"nativeReportStatus", "(JI)Z", (void*)nativeReportStatus},
+        {"nativePrepareImage", "(ILjava/util/Collection;Ljava/util/Collection;)Z", (void*)nativePrepareImage},
+        {"nativeWriteData", "(JLjava/lang/String;JJLandroid/os/ParcelFileDescriptor;)V", (void*)nativeWriteData},
 };
 
 }  // namespace
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1165d2d..44a902c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4113,7 +4113,7 @@
     <permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Must be required by intent filter verifier receiver, to ensure that only the
+    <!-- Must be required by intent filter verifier rintent-filtereceiver, to ensure that only the
          system can interact with it.
          @hide
     -->
@@ -5143,6 +5143,12 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
-</application>
+        <service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader">
+            <intent-filter>
+                <action android:name="android.intent.action.LOAD_DATA" />
+            </intent-filter>
+        </service>
+
+    </application>
 
 </manifest>
diff --git a/core/tests/overlaytests/device/res/layout/layout.xml b/core/tests/overlaytests/device/res/layout/layout.xml
new file mode 100644
index 0000000..e12c715
--- /dev/null
+++ b/core/tests/overlaytests/device/res/layout/layout.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <LinearLayout android:id="@id/view_1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+        <com.android.overlaytest.view.TestTextView
+            android:id="@id/view_2"
+            android:layout_width="match_parent"
+            android:layout_height="100dp"
+            app:customAttribute="none"/>
+
+        <com.android.overlaytest.view.TestTextView
+            android:id="@id/view_3"
+            android:layout_width="match_parent"
+            android:layout_height="100dp"
+            app:customAttribute="none" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/tests/overlaytests/device/res/values/config.xml b/core/tests/overlaytests/device/res/values/config.xml
index c692a262..e918268 100644
--- a/core/tests/overlaytests/device/res/values/config.xml
+++ b/core/tests/overlaytests/device/res/values/config.xml
@@ -56,4 +56,16 @@
         <item>17</item>
         <item>19</item>
     </integer-array>
+
+    <attr name="customAttribute" />
+    <id name="view_1" />
+    <id name="view_2" />
+    <id name="view_3" />
+
+    <!-- Stabilize the ids of attributes and ids used in test layouts so that they differ from the
+     overlay resource ids -->
+    <public type="attr" name="customAttribute" id="0x7f200000"/>
+    <public type="id" name="view_1" id="0x7f210000"/>
+    <public type="id" name="view_2" id="0x7f210001"/>
+    <public type="id" name="view_3" id="0x7f210002"/>
 </resources>
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
index fdb6bbb..636f4c8 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
@@ -18,20 +18,26 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.content.Context;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.os.LocaleList;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.util.Xml;
+import android.view.LayoutInflater;
+import android.view.View;
 
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.overlaytest.view.TestTextView;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -45,6 +51,7 @@
 
 @Ignore
 public abstract class OverlayBaseTest {
+    private Context mContext;
     private Resources mResources;
     private final int mMode;
     static final int MODE_NO_OVERLAY = 0;
@@ -61,7 +68,8 @@
 
     @Before
     public void setUp() {
-        mResources = InstrumentationRegistry.getContext().getResources();
+        mContext = InstrumentationRegistry.getContext();
+        mResources = mContext.getResources();
     }
 
     private int calculateRawResourceChecksum(int resId) throws Throwable {
@@ -321,6 +329,50 @@
         assertEquals("com.android.overlaytest", contents);
     }
 
+    @Test
+    public void testRewrite() throws Throwable {
+        final TypedValue result = new TypedValue();
+        mResources.getValue(R.string.str, result, true);
+        assertEquals(result.resourceId & 0xff000000, 0x7f000000);
+    }
+
+    @Test
+    public void testOverlayLayout() throws Throwable {
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final View layout = inflater.inflate(R.layout.layout, null);
+        assertNotNull(layout.findViewById(R.id.view_1));
+
+        final TestTextView view2 = layout.findViewById(R.id.view_2);
+        assertNotNull(view2);
+        switch (mMode) {
+            case MODE_NO_OVERLAY:
+                assertEquals("none", view2.getCustomAttributeValue());
+                break;
+            case MODE_SINGLE_OVERLAY:
+                assertEquals("single", view2.getCustomAttributeValue());
+                break;
+            case MODE_MULTIPLE_OVERLAYS:
+                assertEquals("multiple", view2.getCustomAttributeValue());
+                break;
+            default:
+                fail("Unknown mode " + mMode);
+        }
+
+        final TestTextView view3 = layout.findViewById(R.id.view_3);
+        assertNotNull(view3);
+        switch (mMode) {
+            case MODE_NO_OVERLAY:
+                assertEquals("none", view3.getCustomAttributeValue());
+                break;
+            case MODE_SINGLE_OVERLAY:
+            case MODE_MULTIPLE_OVERLAYS:
+                assertEquals("overlaid", view3.getCustomAttributeValue());
+                break;
+            default:
+                fail("Unknown mode " + mMode);
+        }
+    }
+
     /*
      * testMatrix* tests
      *
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/view/TestTextView.java b/core/tests/overlaytests/device/src/com/android/overlaytest/view/TestTextView.java
new file mode 100644
index 0000000..2245e2b
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/view/TestTextView.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.overlaytest.view;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+public class TestTextView extends TextView {
+
+    private final String mCustomAttributeValue;
+
+    public TestTextView(Context context, AttributeSet attrs) {
+        this(context, attrs, com.android.internal.R.attr.textViewStyle, 0);
+    }
+
+    public TestTextView(Context context, AttributeSet attrs,
+            int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        int[] testResources = new int[]{com.android.overlaytest.R.attr.customAttribute};
+        final Resources.Theme theme = context.getTheme();
+        TypedArray typedArray = theme.obtainStyledAttributes(attrs, testResources, defStyleAttr,
+                defStyleRes);
+        mCustomAttributeValue = typedArray.getString(0);
+    }
+
+    public String getCustomAttributeValue() {
+        return mCustomAttributeValue;
+    }
+}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
index 7d28408..873ca3c 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
@@ -19,5 +19,6 @@
         android:versionCode="1"
         android:versionName="1.0">
         <application android:hasCode="false" />
-        <overlay android:targetPackage="com.android.overlaytest" />
+        <overlay android:targetPackage="com.android.overlaytest"
+                 android:resourcesMap="@xml/overlays"/>
 </manifest>
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/layout/layout.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/layout/layout.xml
new file mode 100644
index 0000000..7b63605
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/layout/layout.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <LinearLayout android:id="@+id/view_1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+        <com.android.overlaytest.view.TestTextView
+            android:id="@+id/view_2"
+            android:layout_width="match_parent"
+            android:layout_height="100dp"
+            app:customAttribute="@string/str" />
+
+        <com.android.overlaytest.view.TestTextView
+            android:id="@+id/view_3"
+            android:layout_width="match_parent"
+            android:layout_height="100dp"
+            app:customAttribute="overlaid" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml
index 972137a..74c4963 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <string name="str">single</string>
-    <string name="str2">single</string>
     <integer name="matrix_101000">300</integer>
     <integer name="matrix_101001">300</integer>
     <integer name="matrix_101010">300</integer>
@@ -18,7 +17,6 @@
     <integer name="matrix_111101">300</integer>
     <integer name="matrix_111110">300</integer>
     <integer name="matrix_111111">300</integer>
-    <bool name="usually_false">true</bool>
     <integer-array name="fibonacci">
         <item>21</item>
         <item>13</item>
@@ -29,7 +27,10 @@
         <item>1</item>
         <item>1</item>
     </integer-array>
+
     <!-- The following integer does not exist in the original package. Idmap
          generation should therefore ignore it. -->
     <integer name="integer_not_in_original_package">0</integer>
+
+    <attr name="customAttribute" />
 </resources>
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
new file mode 100644
index 0000000..38e5fa1
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<overlay>
+    <item target="drawable/drawable" value="@drawable/drawable"/>
+    <item target="layout/layout" value="@layout/layout"/>
+    <item target="raw/lorem_ipsum" value="@raw/lorem_ipsum"/>
+    <item target="xml/integer" value="@xml/integer"/>
+    <item target="string/str" value="@string/str"/>
+    <item target="string/str2" value="single"/>
+
+    <item target="integer/matrix_100100" value="@integer/matrix_100100"/>
+    <item target="integer/matrix_100101" value="@integer/matrix_100101"/>
+    <item target="integer/matrix_100110" value="@integer/matrix_100110"/>
+    <item target="integer/matrix_100110" value="@integer/matrix_100110"/>
+    <item target="integer/matrix_100111" value="@integer/matrix_100111"/>
+    <item target="integer/matrix_101000" value="@integer/matrix_101000"/>
+    <item target="integer/matrix_101001" value="@integer/matrix_101001"/>
+    <item target="integer/matrix_101010" value="@integer/matrix_101010"/>
+    <item target="integer/matrix_101011" value="@integer/matrix_101011"/>
+    <item target="integer/matrix_101100" value="@integer/matrix_101100"/>
+    <item target="integer/matrix_101101" value="@integer/matrix_101101"/>
+    <item target="integer/matrix_101110" value="@integer/matrix_101110"/>
+    <item target="integer/matrix_101111" value="@integer/matrix_101111"/>
+    <item target="integer/matrix_110100" value="@integer/matrix_110100"/>
+    <item target="integer/matrix_110101" value="@integer/matrix_110101"/>
+    <item target="integer/matrix_110110" value="@integer/matrix_110110"/>
+    <item target="integer/matrix_110111" value="@integer/matrix_110111"/>
+    <item target="integer/matrix_111000" value="@integer/matrix_111000"/>
+    <item target="integer/matrix_111001" value="@integer/matrix_111001"/>
+    <item target="integer/matrix_111010" value="@integer/matrix_111010"/>
+    <item target="integer/matrix_111011" value="@integer/matrix_111011"/>
+    <item target="integer/matrix_111100" value="@integer/matrix_111100"/>
+    <item target="integer/matrix_111101" value="@integer/matrix_111101"/>
+    <item target="integer/matrix_111110" value="@integer/matrix_111110"/>
+    <item target="integer/matrix_111111" value="@integer/matrix_111111"/>
+
+    <item target="bool/usually_false" value="true"/>
+
+    <item target="array/fibonacci" value="@array/fibonacci"/>
+
+    <item target="attr/customAttribute" value="@attr/customAttribute"/>
+    <item target="id/view_1" value="@id/view_1"/>
+    <item target="id/view_2" value="@id/view_2"/>
+    <item target="id/view_3" value="@id/view_3"/>
+</overlay>
+
+
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index ce3bfff..0b2fd9e 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -57,7 +57,7 @@
 
 const char16_t* OverlayStringPool::stringAt(size_t idx, size_t* outLen) const {
   const size_t offset = dtohl(data_header_->string_pool_index_offset);
-  if (idmap_string_pool_ != nullptr && idx >= size() && idx >= offset) {
+  if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
     return idmap_string_pool_->stringAt(idx - offset, outLen);
   }
 
@@ -66,13 +66,17 @@
 
 const char* OverlayStringPool::string8At(size_t idx, size_t* outLen) const {
   const size_t offset = dtohl(data_header_->string_pool_index_offset);
-  if (idmap_string_pool_ != nullptr && idx >= size() && idx >= offset) {
+  if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
     return idmap_string_pool_->string8At(idx - offset, outLen);
   }
 
   return ResStringPool::string8At(idx, outLen);
 }
 
+size_t OverlayStringPool::size() const {
+  return ResStringPool::size() + (idmap_string_pool_ != nullptr ? idmap_string_pool_->size() : 0U);
+}
+
 OverlayDynamicRefTable::OverlayDynamicRefTable(const Idmap_data_header* data_header,
                                                const Idmap_overlay_entry* entries,
                                                uint8_t target_assigned_package_id)
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index ab4c9c2..ccb57f3 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -40,8 +40,9 @@
 class OverlayStringPool : public ResStringPool {
  public:
   virtual ~OverlayStringPool();
-  virtual const char16_t* stringAt(size_t idx, size_t* outLen) const;
-  virtual const char* string8At(size_t idx, size_t* outLen) const;
+  const char16_t* stringAt(size_t idx, size_t* outLen) const override;
+  const char* string8At(size_t idx, size_t* outLen) const override;
+  size_t size() const override;
 
   explicit OverlayStringPool(const LoadedIdmap* loaded_idmap);
  private:
@@ -53,8 +54,8 @@
 // resources to the resource id of corresponding target resources.
 class OverlayDynamicRefTable : public DynamicRefTable {
  public:
-  virtual ~OverlayDynamicRefTable() = default;
-  virtual status_t lookupResourceId(uint32_t* resId) const;
+  ~OverlayDynamicRefTable() override = default;
+  status_t lookupResourceId(uint32_t* resId) const override;
 
  private:
   explicit OverlayDynamicRefTable(const Idmap_data_header* data_header,
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index b603326..35cebd4 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -520,7 +520,7 @@
 
     ssize_t indexOfString(const char16_t* str, size_t strLen) const;
 
-    size_t size() const;
+    virtual size_t size() const;
     size_t styleCount() const;
     size_t bytes() const;
     const void* data() const;
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index 37aca08..b82d8e2 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -18,6 +18,7 @@
 
 #include <binder/Parcel.h>
 #include <jni.h>
+#include <media/IMediaMetricsService.h>
 #include <media/MediaMetricsItem.h>
 #include <nativehelper/JNIHelp.h>
 #include <variant>
@@ -150,14 +151,12 @@
         return (jint)BAD_VALUE;
     }
 
-    // TODO: directly record item to MediaMetrics service.
-    mediametrics::Item item;
-    if (item.readFromByteString((char *)buffer, length) != NO_ERROR) {
-        ALOGW("%s: cannot read from byte string", __func__);
-        return (jint)BAD_VALUE;
+    sp<IMediaMetricsService> service = mediametrics::BaseItem::getService();
+    if (service == nullptr) {
+        ALOGW("Cannot retrieve mediametrics service");
+        return (jint)NO_INIT;
     }
-    item.selfrecord();
-    return (jint)NO_ERROR;
+    return (jint)service->submitBuffer((char *)buffer, length);
 }
 
 // Helper function to convert a native PersistableBundle to a Java
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index f0aa4c3..0c1e9a2 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -26,11 +26,15 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include <android/api-level.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaMuxer.h>
 
+extern "C" int android_get_application_target_sdk_version();
+
 namespace android {
 
 struct fields_t {
@@ -229,10 +233,31 @@
 
     status_t err = muxer->stop();
 
-    if (err != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                          "Failed to stop the muxer");
-        return;
+    if (android_get_application_target_sdk_version() >= __ANDROID_API_R__) {
+        switch (err) {
+            case OK:
+                break;
+            case ERROR_IO: {
+                jniThrowException(env, "java/lang/UncheckedIOException",
+                                  "Muxer stopped unexpectedly");
+                return;
+            }
+            case ERROR_MALFORMED: {
+                jniThrowException(env, "java/io/IOError",
+                                  "Failure of reading or writing operation");
+                return;
+            }
+            default: {
+                jniThrowException(env, "java/lang/IllegalStateException",
+                                  "Failed to stop the muxer");
+                return;
+            }
+        }
+    } else {
+        if (err != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException", "Failed to stop the muxer");
+            return;
+        }
     }
 }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
index ab1feef..38d5211b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
@@ -27,7 +27,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 
 import javax.inject.Inject;
@@ -54,7 +54,7 @@
     private final ContentResolver mContentResolver;
 
     @Inject
-    public CarDeviceProvisionedControllerImpl(Context context, @MainHandler Handler mainHandler,
+    public CarDeviceProvisionedControllerImpl(Context context, @Main Handler mainHandler,
             BroadcastDispatcher broadcastDispatcher) {
         super(context, mainHandler, broadcastDispatcher);
         mContentResolver = context.getContentResolver();
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index e0b0922..59a084e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -35,7 +35,7 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarDeviceProvisionedListener;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NavigationBarController;
@@ -93,7 +93,7 @@
             DeviceProvisionedController deviceProvisionedController,
             CommandQueue commandQueue,
             Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListenerLazy,
-            @MainHandler Handler mainHandler,
+            @Main Handler mainHandler,
             Lazy<KeyguardStateController> keyguardStateControllerLazy,
             Lazy<NavigationBarController> navigationBarControllerLazy,
             SuperStatusBarViewFactory superStatusBarViewFactory,
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
index 2d57be1..b2f8aad 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
@@ -37,7 +37,7 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -68,7 +68,7 @@
     private OnHideListener mOnHideListener;
 
     @Inject
-    CarTrustAgentUnlockDialogHelper(Context context, @MainResources Resources resources,
+    CarTrustAgentUnlockDialogHelper(Context context, @Main Resources resources,
             UserManager userManager, WindowManager windowManager) {
         mContext = context;
         mResources = resources;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 3d74868..f8fc3bb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -38,7 +38,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
 import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener;
 import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
 
@@ -78,7 +78,7 @@
     @Inject
     public FullscreenUserSwitcher(
             Context context,
-            @MainResources Resources resources,
+            @Main Resources resources,
             UserManager userManager,
             CarServiceProvider carServiceProvider,
             CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper) {
diff --git a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
index de92fcd5..4e49302 100644
--- a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
+++ b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
@@ -177,8 +177,7 @@
                   android::dataloader::ServiceParamsPtr) final {
         CHECK(ifs) << "ifs can't be null";
         CHECK(statusListener) << "statusListener can't be null";
-        ALOGE("[AdbDataLoader] onCreate: %s/%s/%d", params.staticArgs().c_str(),
-              params.packageName().c_str(), (int)params.dynamicArgs().size());
+        ALOGE("[AdbDataLoader] onCreate: %d/%s/%s/%s/%d", params.type(), params.packageName().c_str(), params.className().c_str(), params.arguments().c_str(), (int)params.dynamicArgs().size());
 
         if (params.dynamicArgs().empty()) {
             ALOGE("[AdbDataLoader] Invalid DataLoaderParams. Need in/out FDs.");
@@ -204,7 +203,7 @@
         }
 
         std::string logFile;
-        if (const auto packageName = extractPackageName(params.staticArgs()); !packageName.empty()) {
+        if (const auto packageName = extractPackageName(params.arguments()); !packageName.empty()) {
             logFile = android::base::GetProperty("adb.readlog." + packageName, "");
         }
         if (logFile.empty()) {
@@ -288,8 +287,7 @@
                           "inode=%d. Ignore.",
                           static_cast<int>(ino));
                     mRequestedFiles.erase(fileId);
-                    mStatusListener->reportStatus(
-                            INCREMENTAL_DATA_LOADER_NO_CONNECTION);
+                    mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
                 }
             }
             sendRequest(mOutFd, BLOCK_MISSING, fileId, blockIdx);
@@ -337,7 +335,7 @@
             }
             if (res < 0) {
                 ALOGE("[AdbDataLoader] failed to poll. Abort.");
-                mStatusListener->reportStatus(INCREMENTAL_DATA_LOADER_NO_CONNECTION);
+                mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
                 break;
             }
             if (res == mEventFd) {
@@ -346,7 +344,7 @@
             }
             if (!readChunk(mInFd, data)) {
                 ALOGE("[AdbDataLoader] failed to read a message. Abort.");
-                mStatusListener->reportStatus(INCREMENTAL_DATA_LOADER_NO_CONNECTION);
+                mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
                 break;
             }
             auto remainingData = std::span(data);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 4fb3be2..c238d7d 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -42,6 +42,7 @@
         "res",
     ],
     static_libs: [
+        "WindowManager-Shell",
         "SystemUIPluginLib",
         "SystemUISharedLib",
         "SettingsLib",
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index caf5ee0..255693b 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -43,7 +43,7 @@
 import com.android.settingslib.WirelessUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 
 import java.util.List;
@@ -608,7 +608,7 @@
         private boolean mShowMissingSim;
 
         @Inject
-        public Builder(Context context, @MainResources Resources resources) {
+        public Builder(Context context, @Main Resources resources) {
             mContext = context;
             mSeparator = resources.getString(
                     com.android.internal.R.string.kg_text_message_separator);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fb7a269..694c623 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -101,7 +101,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainLooper;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -1496,7 +1496,7 @@
 
     @VisibleForTesting
     @Inject
-    protected KeyguardUpdateMonitor(Context context, @MainLooper Looper mainLooper,
+    protected KeyguardUpdateMonitor(Context context, @Main Looper mainLooper,
             BroadcastDispatcher broadcastDispatcher,
             DumpController dumpController) {
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 94e7c68c..a9ca04b 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -39,10 +39,8 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.BgLooper;
-import com.android.systemui.dagger.qualifiers.MainHandler;
-import com.android.systemui.dagger.qualifiers.MainLooper;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.ScreenLifecycle;
@@ -297,10 +295,10 @@
     @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
     @Inject Lazy<AutoHideController> mAutoHideController;
     @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
-    @Inject @BgLooper Lazy<Looper> mBgLooper;
-    @Inject @BgHandler Lazy<Handler> mBgHandler;
-    @Inject @MainLooper Lazy<Looper> mMainLooper;
-    @Inject @MainHandler Lazy<Handler> mMainHandler;
+    @Inject @Background Lazy<Looper> mBgLooper;
+    @Inject @Background Lazy<Handler> mBgHandler;
+    @Inject @Main Lazy<Looper> mMainLooper;
+    @Inject @Main Lazy<Handler> mMainHandler;
     @Inject @Named(TIME_TICK_HANDLER_NAME) Lazy<Handler> mTimeTickHandler;
     @Nullable
     @Inject @Named(LEAK_REPORT_EMAIL_NAME) Lazy<String> mLeakReportEmail;
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index 41dd5bbf..82e665b 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -24,7 +24,7 @@
 
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.util.Assert;
@@ -50,7 +50,7 @@
 
     @Inject
     public ForegroundServiceController(NotificationEntryManager entryManager,
-            AppOpsController appOpsController, @MainHandler Handler mainHandler) {
+            AppOpsController appOpsController, @Main Handler mainHandler) {
         mEntryManager = entryManager;
         mMainHandler = mainHandler;
         appOpsController.addCallback(APP_OPS, (code, uid, packageName, active) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 9ce277e..0e736dc 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -68,7 +68,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.plugins.qs.QS;
@@ -147,7 +147,7 @@
     @Inject
     public ScreenDecorations(Context context,
             Lazy<StatusBar> statusBarLazy,
-            @MainHandler Handler handler,
+            @Main Handler handler,
             BroadcastDispatcher broadcastDispatcher,
             TunerService tunerService) {
         super(context);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 1645957..41d8314 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -27,7 +27,7 @@
 import android.util.Slog;
 
 import com.android.internal.os.BinderInternal;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
 
@@ -41,7 +41,7 @@
     private final Handler mMainHandler;
 
     @Inject
-    public SystemUIService(@MainHandler Handler mainHandler) {
+    public SystemUIService(@Main Handler mainHandler) {
         super();
         mMainHandler = mainHandler;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 6178ff2..895207d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -22,7 +22,7 @@
 import android.provider.Settings;
 
 import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -36,7 +36,7 @@
     private final Handler mHandler;
 
     @Inject
-    public WindowMagnification(Context context, @MainHandler Handler mainHandler) {
+    public WindowMagnification(Context context, @Main Handler mainHandler) {
         super(context);
         mHandler = mainHandler;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index bad6b54..b083123 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -30,7 +30,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.Background;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -81,7 +81,7 @@
     };
 
     @Inject
-    public AppOpsControllerImpl(Context context, @BgLooper Looper bgLooper,
+    public AppOpsControllerImpl(Context context, @Background Looper bgLooper,
             DumpController dumpController) {
         this(context, bgLooper, new PermissionFlagsCache(context), dumpController);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index 5cc70bc..8cb0cc5 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -28,8 +28,8 @@
 import android.util.SparseArray
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.Dumpable
-import com.android.systemui.dagger.qualifiers.BgLooper
-import com.android.systemui.dagger.qualifiers.MainHandler
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import javax.inject.Inject
@@ -62,8 +62,8 @@
 @Singleton
 open class BroadcastDispatcher @Inject constructor (
     private val context: Context,
-    @MainHandler private val mainHandler: Handler,
-    @BgLooper private val bgLooper: Looper
+    @Main private val mainHandler: Handler,
+    @Background private val bgLooper: Looper
 ) : Dumpable {
 
     // Only modify in BG thread
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index db85fa0..4663b1c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -30,7 +30,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
 import com.android.systemui.classifier.brightline.FalsingDataProvider;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.FalsingPlugin;
 import com.android.systemui.plugins.PluginListener;
@@ -61,7 +61,7 @@
 
     @Inject
     FalsingManagerProxy(Context context, PluginManager pluginManager,
-            @MainHandler Handler handler,
+            @Main Handler handler,
             ProximitySensor proximitySensor,
             DeviceConfigProxy deviceConfig) {
         mProximitySensor = proximitySensor;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 0d161ce..8d10552 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -25,8 +25,6 @@
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Process;
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
 import android.view.IWindowManager;
@@ -35,10 +33,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.BgLooper;
-import com.android.systemui.dagger.qualifiers.MainHandler;
-import com.android.systemui.dagger.qualifiers.MainLooper;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.PluginInitializerImpl;
@@ -82,35 +78,6 @@
         return new Handler(thread.getLooper());
     }
 
-    @Singleton
-    @Provides
-    @BgLooper
-    public Looper provideBgLooper() {
-        HandlerThread thread = new HandlerThread("SysUiBg",
-                Process.THREAD_PRIORITY_BACKGROUND);
-        thread.start();
-        return thread.getLooper();
-    }
-
-    /** Main Looper */
-    @Provides
-    @MainLooper
-    public Looper provideMainLooper() {
-        return Looper.getMainLooper();
-    }
-
-    @Provides
-    @BgHandler
-    public Handler provideBgHandler(@BgLooper Looper bgLooper) {
-        return new Handler(bgLooper);
-    }
-
-    @Provides
-    @MainHandler
-    public Handler provideMainHandler(@MainLooper Looper mainLooper) {
-        return new Handler(mainLooper);
-    }
-
     /** */
     @Provides
     public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
@@ -175,7 +142,7 @@
     @Singleton
     @Provides
     public NightDisplayListener provideNightDisplayListener(Context context,
-            @BgHandler Handler bgHandler) {
+            @Background Handler bgHandler) {
         return new NightDisplayListener(context, bgHandler);
     }
 
@@ -188,7 +155,7 @@
     @Singleton
     @Provides
     public NavigationBarController provideNavigationBarController(Context context,
-            @MainHandler Handler mainHandler, CommandQueue commandQueue) {
+            @Main Handler mainHandler, CommandQueue commandQueue) {
         return new NavigationBarController(context, mainHandler, commandQueue);
     }
 
@@ -201,7 +168,7 @@
     @Singleton
     @Provides
     public AutoHideController provideAutoHideController(Context context,
-            @MainHandler Handler mainHandler,
+            @Main Handler mainHandler,
             NotificationRemoteInputManager notificationRemoteInputManager,
             IWindowManager iWindowManager) {
         return new AutoHideController(context, mainHandler, notificationRemoteInputManager,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index 534f350..0b73ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -44,8 +44,8 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.LatencyTracker;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.system.PackageManagerWrapper;
 
 import javax.inject.Singleton;
@@ -126,7 +126,7 @@
     @Provides
     @Nullable
     static LocalBluetoothManager provideLocalBluetoothController(Context context,
-            @BgHandler Handler bgHandler) {
+            @Background Handler bgHandler) {
         return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
     }
 
@@ -150,7 +150,7 @@
     }
 
     @Provides
-    @MainResources
+    @Main
     static Resources provideResources(Context context) {
         return context.getResources();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgLooper.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgLooper.java
deleted file mode 100644
index 2aadda1..0000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgLooper.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.dagger.qualifiers;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface BgLooper {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainHandler.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainHandler.java
deleted file mode 100644
index 79661fa..0000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainHandler.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.dagger.qualifiers;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface MainHandler {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainLooper.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainLooper.java
deleted file mode 100644
index 750d7d7..0000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainLooper.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.dagger.qualifiers;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface MainLooper {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainResources.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainResources.java
deleted file mode 100644
index 3daeda5..0000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainResources.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.dagger.qualifiers;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface MainResources {
-    // TODO: use attribute to get other, non-main resources?
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java
index ac94858..fb10642 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroupController.java
@@ -32,8 +32,8 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.keyguard.CarrierTextController;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.MainLooper;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.policy.NetworkController;
 
@@ -111,7 +111,7 @@
     }
 
     private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter,
-            @BgHandler Handler bgHandler, @MainLooper Looper mainLooper,
+            @Background Handler bgHandler, @Main Looper mainLooper,
             NetworkController networkController,
             CarrierTextController.Builder carrierTextControllerBuilder) {
         mActivityStarter = activityStarter;
@@ -308,8 +308,8 @@
         private final CarrierTextController.Builder mCarrierTextControllerBuilder;
 
         @Inject
-        public Builder(ActivityStarter activityStarter, @BgHandler Handler handler,
-                @MainLooper Looper looper, NetworkController networkController,
+        public Builder(ActivityStarter activityStarter, @Background Handler handler,
+                @Main Looper looper, NetworkController networkController,
                 CarrierTextController.Builder carrierTextControllerBuilder) {
             mActivityStarter = activityStarter;
             mHandler = handler;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index c01bc8fe..86ed274 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -34,8 +34,8 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.BgLooper;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
@@ -96,8 +96,8 @@
     public QSTileHost(Context context,
             StatusBarIconController iconController,
             QSFactoryImpl defaultFactory,
-            @MainHandler Handler mainHandler,
-            @BgLooper Looper bgLooper,
+            @Main Handler mainHandler,
+            @Background Looper bgLooper,
             PluginManager pluginManager,
             TunerService tunerService,
             Provider<AutoTileManager> autoTiles,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index c9813db..02c4beb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -68,7 +68,7 @@
 import android.widget.Toast;
 
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
 
@@ -186,7 +186,7 @@
      */
     @Inject
     public GlobalScreenshot(
-            Context context, @MainResources Resources resources, LayoutInflater layoutInflater,
+            Context context, @Main Resources resources, LayoutInflater layoutInflater,
             ScreenshotNotificationsController screenshotNotificationsController) {
         mContext = context;
         mNotificationsController = screenshotNotificationsController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 61043fb..a8188b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -35,7 +35,7 @@
 import com.android.internal.statusbar.RegisterStatusBarResult;
 import com.android.systemui.Dependency;
 import com.android.systemui.assist.AssistHandleViewController;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -65,7 +65,7 @@
     SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
 
     @Inject
-    public NavigationBarController(Context context, @MainHandler Handler handler,
+    public NavigationBarController(Context context, @Main Handler handler,
             CommandQueue commandQueue) {
         mContext = context;
         mHandler = handler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 97dd3da..8dd801b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -30,7 +30,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
 
 import java.util.ArrayList;
@@ -58,7 +58,7 @@
     public NotificationListener(
             Context context,
             NotificationManager notificationManager,
-            @MainHandler Handler mainHandler) {
+            @Main Handler mainHandler) {
         mContext = context;
         mNotificationManager = notificationManager;
         mMainHandler = mainHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 0f3f6b7..2e369b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -48,7 +48,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.recents.OverviewProxyService;
@@ -190,7 +190,7 @@
             IStatusBarService iStatusBarService,
             KeyguardManager keyguardManager,
             StatusBarStateController statusBarStateController,
-            @MainHandler Handler mainHandler,
+            @Main Handler mainHandler,
             DeviceProvisionedController deviceProvisionedController,
             KeyguardStateController keyguardStateController) {
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index f6f3ac1..43d0399 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -50,7 +50,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -263,7 +263,7 @@
             NotificationEntryManager notificationEntryManager,
             Lazy<StatusBar> statusBarLazy,
             StatusBarStateController statusBarStateController,
-            @MainHandler Handler mainHandler,
+            @Main Handler mainHandler,
             RemoteInputUriController remoteInputUriController) {
         mContext = context;
         mLockscreenUserManager = lockscreenUserManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 1648196..6b0b5df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -27,7 +27,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -93,7 +93,7 @@
     private boolean mIsHandleDynamicPrivacyChangeScheduled;
 
     @Inject
-    public NotificationViewHierarchyManager(Context context, @MainHandler Handler mainHandler,
+    public NotificationViewHierarchyManager(Context context, @Main Handler mainHandler,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             NotificationGroupManager groupManager,
             VisualStabilityManager visualStabilityManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 1b57308..99718abb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -23,7 +23,7 @@
 import androidx.collection.ArraySet;
 
 import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -62,7 +62,7 @@
 
     @Inject
     public VisualStabilityManager(
-            NotificationEntryManager notificationEntryManager, @MainHandler Handler handler) {
+            NotificationEntryManager notificationEntryManager, @Main Handler handler) {
 
         mHandler = handler;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
index ee841c2..62342b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
@@ -24,7 +24,7 @@
 
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
@@ -63,7 +63,7 @@
     public ForegroundCoordinator(
             ForegroundServiceController foregroundServiceController,
             AppOpsController appOpsController,
-            @MainHandler Handler mainHandler) {
+            @Main Handler mainHandler) {
         mForegroundServiceController = foregroundServiceController;
         mAppOpsController = appOpsController;
         mMainHandler = mainHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
index e9d6a0f..ec1d6de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
@@ -23,7 +23,7 @@
 import android.os.UserHandle
 import android.provider.Settings
 import android.view.View
-import com.android.systemui.dagger.qualifiers.MainHandler
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager
 import javax.inject.Inject
@@ -164,7 +164,7 @@
 
 @Singleton
 class PeopleHubSettingChangeDataSourceImpl @Inject constructor(
-    @MainHandler private val handler: Handler,
+    @Main private val handler: Handler,
     context: Context
 ) : DataSource<Boolean> {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 9dd7f48..6f2abba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -42,7 +42,7 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
@@ -108,7 +108,7 @@
 
     @Inject
     public NotificationGutsManager(Context context, VisualStabilityManager visualStabilityManager,
-            Lazy<StatusBar> statusBarLazy, @MainHandler Handler mainHandler,
+            Lazy<StatusBar> statusBarLazy, @Main Handler mainHandler,
             AccessibilityManager accessibilityManager) {
         mContext = context;
         mVisualStabilityManager = visualStabilityManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index f9b9367..3165597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -23,7 +23,7 @@
 import android.view.IWindowManager;
 import android.view.MotionEvent;
 
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 
 import javax.inject.Inject;
@@ -52,7 +52,7 @@
     };
 
     @Inject
-    public AutoHideController(Context context, @MainHandler Handler handler,
+    public AutoHideController(Context context, @Main Handler handler,
             NotificationRemoteInputManager notificationRemoteInputManager,
             IWindowManager iWindowManager) {
         mHandler = handler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 837517e..0680c7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -21,7 +21,7 @@
 import android.provider.Settings.Secure;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.SecureSetting;
@@ -57,7 +57,7 @@
 
     @Inject
     public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
-            @BgHandler Handler handler,
+            @Background Handler handler,
             HotspotController hotspotController,
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 250f730..4880520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -37,7 +37,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -165,7 +165,7 @@
             StatusBarWindowController statusBarWindowController,
             KeyguardStateController keyguardStateController, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            @MainResources Resources resources,
+            @Main Resources resources,
             KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters,
             MetricsLogger metricsLogger, DumpController dumpController) {
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index bc48235..f5999f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -25,7 +25,7 @@
 import android.util.MathUtils;
 
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.doze.DozeScreenState;
 import com.android.systemui.tuner.TunerService;
@@ -58,7 +58,7 @@
 
     @Inject
     protected DozeParameters(
-            @MainResources Resources resources,
+            @Main Resources resources,
             AmbientDisplayConfiguration ambientDisplayConfiguration,
             AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
             PowerManager powerManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 183adeb..4ee13bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -43,7 +43,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.NotificationMediaManager;
 
 import libcore.io.IoUtils;
@@ -83,7 +83,7 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             DumpController dumpController,
             NotificationMediaManager mediaManager,
-            @MainHandler Handler mainHandler) {
+            @Main Handler mainHandler) {
         dumpController.registerDumpable(getClass().getSimpleName(), this);
         mWallpaperManager = wallpaperManager;
         mCurrentUserId = ActivityManager.getCurrentUser();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index ebe2117..d4cf272 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -93,7 +93,7 @@
 import com.android.systemui.assist.AssistHandleViewController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.model.SysUiState;
@@ -274,7 +274,7 @@
             CommandQueue commandQueue, Divider divider,
             Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
             ShadeController shadeController,
-            @MainHandler Handler mainHandler) {
+            @Main Handler mainHandler) {
         mAccessibilityManagerWrapper = accessibilityManagerWrapper;
         mDeviceProvisionedController = deviceProvisionedController;
         mStatusBarStateController = statusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 4c5bbce..2b9fc8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -45,7 +45,7 @@
 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.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -192,7 +192,7 @@
     @Inject
     public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
             AlarmManager alarmManager, KeyguardStateController keyguardStateController,
-            @MainResources Resources resources,
+            @Main Resources resources,
             DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
             DockManager dockManager) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 3123f8d..fa584d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -52,8 +52,8 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -549,8 +549,8 @@
                 NotificationInterruptionStateProvider notificationInterruptionStateProvider,
                 MetricsLogger metricsLogger,
                 LockPatternUtils lockPatternUtils,
-                @MainHandler Handler mainThreadHandler,
-                @BgHandler Handler backgroundHandler,
+                @Main Handler mainThreadHandler,
+                @Background Handler backgroundHandler,
                 ActivityIntentHelper activityIntentHelper,
                 BubbleController bubbleController,
                 ShadeController shadeController,
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 f94b2ee..ce498a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -41,7 +41,7 @@
 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.dagger.qualifiers.Main;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -105,7 +105,7 @@
             ConfigurationController configurationController,
             KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor,
             SuperStatusBarViewFactory superStatusBarViewFactory,
-            @MainResources Resources resources) {
+            @Main Resources resources) {
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index dc80906..f132058 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -34,8 +34,8 @@
 import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.power.EnhancedEstimates;
 
 import java.io.FileDescriptor;
@@ -82,7 +82,7 @@
     @Inject
     BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
             PowerManager powerManager, BroadcastDispatcher broadcastDispatcher,
-            @MainHandler Handler mainHandler, @BgHandler Handler bgHandler) {
+            @Main Handler mainHandler, @Background Handler bgHandler) {
         mContext = context;
         mMainHandler = mainHandler;
         mBgHandler = bgHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 6ededd246..0fc3d84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -34,8 +34,8 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
-import com.android.systemui.dagger.qualifiers.BgLooper;
-import com.android.systemui.dagger.qualifiers.MainLooper;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -75,8 +75,8 @@
     /**
      */
     @Inject
-    public BluetoothControllerImpl(Context context, @BgLooper Looper bgLooper,
-            @MainLooper Looper mainLooper, @Nullable LocalBluetoothManager localBluetoothManager) {
+    public BluetoothControllerImpl(Context context, @Background Looper bgLooper,
+            @Main Looper mainLooper, @Nullable LocalBluetoothManager localBluetoothManager) {
         mLocalBluetoothManager = localBluetoothManager;
         mBgHandler = new Handler(bgLooper);
         mHandler = new H(mainLooper);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index f6b770c..a3e2e76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -25,7 +25,7 @@
 import android.util.Log;
 
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.settings.CurrentUserTracker;
 
 import java.util.ArrayList;
@@ -50,7 +50,7 @@
     /**
      */
     @Inject
-    public DeviceProvisionedControllerImpl(Context context, @MainHandler Handler mainHandler,
+    public DeviceProvisionedControllerImpl(Context context, @Main Handler mainHandler,
             BroadcastDispatcher broadcastDispatcher) {
         super(broadcastDispatcher);
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index cd6ec05..df9c3f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -26,7 +26,7 @@
 import android.os.UserManager;
 import android.util.Log;
 
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -59,7 +59,7 @@
      * Controller used to retrieve information related to a hotspot.
      */
     @Inject
-    public HotspotControllerImpl(Context context, @MainHandler Handler mainHandler) {
+    public HotspotControllerImpl(Context context, @Main Handler mainHandler) {
         mContext = context;
         mConnectivityManager =
                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index d36bd75..570f153 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -37,7 +37,7 @@
 
 import com.android.systemui.BootCompleteCache;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
@@ -69,7 +69,7 @@
     private final H mHandler = new H();
 
     @Inject
-    public LocationControllerImpl(Context context, @BgLooper Looper bgLooper,
+    public LocationControllerImpl(Context context, @Background Looper bgLooper,
             BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 24492bf..f20a47b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -64,7 +64,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
@@ -177,7 +177,7 @@
      * Construct this controller object and register for updates.
      */
     @Inject
-    public NetworkControllerImpl(Context context, @BgLooper Looper bgLooper,
+    public NetworkControllerImpl(Context context, @Background Looper bgLooper,
             DeviceProvisionedController deviceProvisionedController,
             BroadcastDispatcher broadcastDispatcher) {
         this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index c161458..019ef3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -49,7 +49,7 @@
 import com.android.internal.net.VpnConfig;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.settings.CurrentUserTracker;
 
 import java.io.FileDescriptor;
@@ -101,7 +101,7 @@
     /**
      */
     @Inject
-    public SecurityControllerImpl(Context context, @BgHandler Handler bgHandler,
+    public SecurityControllerImpl(Context context, @Background Handler bgHandler,
             BroadcastDispatcher broadcastDispatcher) {
         this(context, bgHandler, broadcastDispatcher, null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index 347d300..86fe3008 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -28,7 +28,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -65,7 +65,7 @@
     private final KeyValueListParser mParser = new KeyValueListParser(',');
 
     @Inject
-    public SmartReplyConstants(@MainHandler Handler handler, Context context) {
+    public SmartReplyConstants(@Main Handler handler, Context context) {
         mHandler = handler;
         mContext = context;
         final Resources resources = mContext.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 13c0db9..2907cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -60,7 +60,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUISecondaryUserService;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.tiles.UserDetailView;
@@ -113,7 +113,7 @@
 
     @Inject
     public UserSwitcherController(Context context, KeyguardStateController keyguardStateController,
-            @MainHandler Handler handler, ActivityStarter activityStarter,
+            @Main Handler handler, ActivityStarter activityStarter,
             BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index a2028e6..4376a01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -40,7 +40,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.util.Utils;
@@ -78,7 +78,7 @@
     private NotificationManager.Policy mConsolidatedNotificationPolicy;
 
     @Inject
-    public ZenModeControllerImpl(Context context, @MainHandler Handler handler,
+    public ZenModeControllerImpl(Context context, @Main Handler handler,
             BroadcastDispatcher broadcastDispatcher) {
         super(broadcastDispatcher);
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index f9d39b0..7758aba 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -36,7 +36,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.Background;
 
 import com.google.android.collect.Sets;
 
@@ -70,7 +70,7 @@
 
     @Inject
     public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher,
-            @BgHandler Handler bgHandler) {
+            @Background Handler bgHandler) {
         super(context);
         mBroadcastDispatcher = broadcastDispatcher;
         mBgHandler = bgHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index ce0032e..19f0ba2 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -35,7 +35,7 @@
 import com.android.systemui.DejankUtils;
 import com.android.systemui.DemoMode;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -82,7 +82,7 @@
     /**
      */
     @Inject
-    public TunerServiceImpl(Context context, @MainHandler Handler mainHandler,
+    public TunerServiceImpl(Context context, @Main Handler mainHandler,
             LeakDetector leakDetector, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mContentResolver = mContext.getContentResolver();
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
index 3e90581..1c5d979 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -18,15 +18,17 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.Process;
 
 import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dagger.qualifiers.MainLooper;
 
 import java.util.concurrent.Executor;
 
+import javax.inject.Singleton;
+
 import dagger.Module;
 import dagger.Provides;
 
@@ -35,11 +37,51 @@
  */
 @Module
 public abstract class ConcurrencyModule {
+    /** Background Looper */
+    @Provides
+    @Singleton
+    @Background
+    public static Looper provideBgLooper() {
+        HandlerThread thread = new HandlerThread("SysUiBg",
+                Process.THREAD_PRIORITY_BACKGROUND);
+        thread.start();
+        return thread.getLooper();
+    }
+
+    /** Main Looper */
+    @Provides
+    @Main
+    public static  Looper provideMainLooper() {
+        return Looper.getMainLooper();
+    }
+
+    /**
+     * Background Handler.
+     *
+     * Prefer the Background Executor when possible.
+     */
+    @Provides
+    @Background
+    public static Handler provideBgHandler(@Background Looper bgLooper) {
+        return new Handler(bgLooper);
+    }
+
+    /**
+     * Main Handler.
+     *
+     * Prefer the Main Executor when possible.
+     */
+    @Provides
+    @Main
+    public static Handler provideMainHandler(@Main Looper mainLooper) {
+        return new Handler(mainLooper);
+    }
+
     /**
      * Provide a Background-Thread Executor by default.
      */
     @Provides
-    public static Executor provideExecutor(@BgLooper Looper looper) {
+    public static Executor provideExecutor(@Background Looper looper) {
         return new ExecutorImpl(new Handler(looper));
     }
 
@@ -48,7 +90,7 @@
      */
     @Provides
     @Background
-    public static Executor provideBackgroundExecutor(@BgLooper Looper looper) {
+    public static Executor provideBackgroundExecutor(@Background Looper looper) {
         return new ExecutorImpl(new Handler(looper));
     }
 
@@ -65,7 +107,7 @@
      * Provide a Background-Thread Executor by default.
      */
     @Provides
-    public static DelayableExecutor provideDelayableExecutor(@BgLooper Looper looper) {
+    public static DelayableExecutor provideDelayableExecutor(@Background Looper looper) {
         return new ExecutorImpl(new Handler(looper));
     }
 
@@ -74,7 +116,7 @@
      */
     @Provides
     @Background
-    public static DelayableExecutor provideBackgroundDelayableExecutor(@BgLooper Looper looper) {
+    public static DelayableExecutor provideBackgroundDelayableExecutor(@Background Looper looper) {
         return new ExecutorImpl(new Handler(looper));
     }
 
@@ -83,7 +125,7 @@
      */
     @Provides
     @Main
-    public static DelayableExecutor provideMainDelayableExecutor(@MainLooper Looper looper) {
+    public static DelayableExecutor provideMainDelayableExecutor(@Main Looper looper) {
         return new ExecutorImpl(new Handler(looper));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index bff405c..2c7c52e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -47,7 +47,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSHost;
@@ -109,7 +109,7 @@
     @Inject
     public GarbageMonitor(
             Context context,
-            @BgLooper Looper bgLooper,
+            @Background Looper bgLooper,
             LeakDetector leakDetector,
             LeakReporter leakReporter) {
         mContext = context.getApplicationContext();
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index a96977a..b5bede4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -26,7 +26,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -65,7 +65,7 @@
     };
 
     @Inject
-    public ProximitySensor(@MainResources Resources resources,
+    public ProximitySensor(@Main Resources resources,
             AsyncSensorManager sensorManager) {
         mSensorManager = sensorManager;
         Sensor sensor = findBrightnessSensor(resources);
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
index aed90eb..951d6dd 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -31,7 +31,7 @@
 import android.view.IWindowManager;
 import android.view.WindowContainerTransaction;
 
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import java.util.ArrayList;
 
@@ -160,7 +160,7 @@
             };
 
     @Inject
-    public DisplayWindowController(Context context, @MainHandler Handler mainHandler,
+    public DisplayWindowController(Context context, @Main Handler mainHandler,
             IWindowManager wmService) {
         mHandler = mainHandler;
         mContext = context;
diff --git a/packages/WindowManager/OWNERS b/packages/WindowManager/OWNERS
new file mode 100644
index 0000000..063d459
--- /dev/null
+++ b/packages/WindowManager/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include ../../services/core/java/com/android/server/wm/OWNERS
\ No newline at end of file
diff --git a/packages/WindowManager/Shell/Android.bp b/packages/WindowManager/Shell/Android.bp
new file mode 100644
index 0000000..b8934dc
--- /dev/null
+++ b/packages/WindowManager/Shell/Android.bp
@@ -0,0 +1,29 @@
+// 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.
+
+android_library {
+    name: "WindowManager-Shell",
+    srcs: [
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+    resource_dirs: [
+        "res",
+    ],
+    manifest: "AndroidManifest.xml",
+
+    platform_apis: true,
+    sdk_version: "current",
+    min_sdk_version: "system_current",
+}
diff --git a/packages/WindowManager/Shell/AndroidManifest.xml b/packages/WindowManager/Shell/AndroidManifest.xml
new file mode 100644
index 0000000..ea8a5c3
--- /dev/null
+++ b/packages/WindowManager/Shell/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.wm.shell">
+</manifest>
diff --git a/packages/WindowManager/Shell/OWNERS b/packages/WindowManager/Shell/OWNERS
new file mode 100644
index 0000000..4390004
--- /dev/null
+++ b/packages/WindowManager/Shell/OWNERS
@@ -0,0 +1,4 @@
+# sysui owners
+hwwang@google.com
+mrenouf@google.com
+winsonc@google.com
\ No newline at end of file
diff --git a/packages/WindowManager/Shell/res/values/config.xml b/packages/WindowManager/Shell/res/values/config.xml
new file mode 100644
index 0000000..c894eb0
--- /dev/null
+++ b/packages/WindowManager/Shell/res/values/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java b/packages/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShell.java
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java
rename to packages/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShell.java
index bc6b83b..273bd27 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java
+++ b/packages/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShell.java
@@ -14,17 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.dagger.qualifiers;
+package com.android.wm.shell;
 
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface BgHandler {
+/**
+ * Interface for the shell.
+ */
+public class WindowManagerShell {
 }
diff --git a/packages/WindowManager/Shell/tests/Android.bp b/packages/WindowManager/Shell/tests/Android.bp
new file mode 100644
index 0000000..78fa45e
--- /dev/null
+++ b/packages/WindowManager/Shell/tests/Android.bp
@@ -0,0 +1,45 @@
+// 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.
+
+android_test {
+    name: "WindowManagerShellTests",
+
+    srcs: ["**/*.java"],
+
+    static_libs: [
+        "WindowManager-Shell",
+        "junit",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "mockito-target-extended-minus-junit4",
+        "truth-prebuilt",
+    ],
+    libs: [
+        "android.test.mock",
+        "android.test.base",
+        "android.test.runner",
+    ],
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+
+    sdk_version: "current",
+    platform_apis: true,
+
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/packages/WindowManager/Shell/tests/AndroidManifest.xml b/packages/WindowManager/Shell/tests/AndroidManifest.xml
new file mode 100644
index 0000000..a8f795e
--- /dev/null
+++ b/packages/WindowManager/Shell/tests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.wm.shell.tests">
+
+    <application android:debuggable="true" android:largeHeap="true">
+        <uses-library android:name="android.test.mock" />
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:label="Tests for WindowManager-Shell"
+        android:targetPackage="com.android.wm.shell.tests">
+    </instrumentation>
+</manifest>
diff --git a/packages/WindowManager/Shell/tests/AndroidTest.xml b/packages/WindowManager/Shell/tests/AndroidTest.xml
new file mode 100644
index 0000000..4dce4db
--- /dev/null
+++ b/packages/WindowManager/Shell/tests/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Tests for WindowManagerShellLib">
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
+        <option name="test-file-name" value="WindowManagerShellTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="WindowManagerShellTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.wm.shell.tests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/packages/WindowManager/Shell/tests/res/values/config.xml b/packages/WindowManager/Shell/tests/res/values/config.xml
new file mode 100644
index 0000000..c894eb0
--- /dev/null
+++ b/packages/WindowManager/Shell/tests/res/values/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources>
+</resources>
\ No newline at end of file
diff --git a/packages/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java b/packages/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java
new file mode 100644
index 0000000..376875b
--- /dev/null
+++ b/packages/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.wm.shell.tests;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.WindowManagerShell;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the shell.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowManagerShellTest {
+
+    WindowManagerShell mShell;
+
+    @Test
+    public void testNothing() {
+        // Do nothing
+    }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 81ce359..26245b1 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -635,7 +635,7 @@
                             mPackageManagerInternal.getSuspendedDialogInfo(providerPackage,
                                     suspendingPackage, providerUserId);
                     onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
-                            providerPackage, suspendingPackage, dialogInfo, providerUserId);
+                            providerPackage, suspendingPackage, dialogInfo, null, providerUserId);
                 }
             } else if (provider.maskedByQuietProfile) {
                 showBadge = true;
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index f363a73..40a7dfc 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -67,6 +67,27 @@
     public static final int PACKAGE_COMPANION = 14;
 
     @IntDef(value = {
+            INTEGRITY_VERIFICATION_ALLOW,
+            INTEGRITY_VERIFICATION_REJECT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IntegrityVerificationResult {}
+
+    /**
+     * Used as the {@code verificationCode} argument for
+     * {@link PackageManagerInternal#setIntegrityVerificationResult(int, int)} to indicate that the
+     * integrity component allows the install to proceed.
+     */
+    public static final int INTEGRITY_VERIFICATION_ALLOW = 1;
+
+    /**
+     * Used as the {@code verificationCode} argument for
+     * {@link PackageManagerInternal#setIntegrityVerificationResult(int, int)} to indicate that the
+     * integrity component does not allow install to proceed.
+     */
+    public static final int INTEGRITY_VERIFICATION_REJECT = 0;
+
+    @IntDef(value = {
         PACKAGE_SYSTEM,
         PACKAGE_SETUP_WIZARD,
         PACKAGE_INSTALLER,
@@ -842,13 +863,13 @@
      * {@link Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION package verification
      * broadcast} to respond to the package manager. The response must include
      * the {@code verificationCode} which is one of
-     * {@link PackageManager#VERIFICATION_ALLOW} or
-     * {@link PackageManager#VERIFICATION_REJECT}.
+     * {@link #INTEGRITY_VERIFICATION_ALLOW} and {@link #INTEGRITY_VERIFICATION_REJECT}.
      *
      * @param verificationId pending package identifier as passed via the
      *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
-     * @param verificationResult either {@link PackageManager#VERIFICATION_ALLOW}
-     *            or {@link PackageManager#VERIFICATION_REJECT}.
+     * @param verificationResult either {@link #INTEGRITY_VERIFICATION_ALLOW}
+     *            or {@link #INTEGRITY_VERIFICATION_REJECT}.
      */
-    public abstract void setIntegrityVerificationResult(int verificationId, int verificationResult);
+    public abstract void setIntegrityVerificationResult(int verificationId,
+            @IntegrityVerificationResult int verificationResult);
 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 13eb556..46ff718 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -46,6 +46,7 @@
 import android.telephony.Annotation.SrvccState;
 import android.telephony.CallAttributes;
 import android.telephony.CallQuality;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
 import android.telephony.DataFailCause;
@@ -207,7 +208,7 @@
     // Connection state of default APN type data (i.e. internet) of phones
     private int[] mDataConnectionState;
 
-    private Bundle[] mCellLocation;
+    private CellIdentity[] mCellIdentity;
 
     private int[] mDataConnectionNetworkType;
 
@@ -295,7 +296,7 @@
                     int numPhones = getTelephonyManager().getPhoneCount();
                     for (int sub = 0; sub < numPhones; sub++) {
                         TelephonyRegistry.this.notifyCellLocationForSubscriber(sub,
-                                mCellLocation[sub]);
+                                mCellIdentity[sub]);
                     }
                     break;
                 }
@@ -404,7 +405,7 @@
         mSignalStrength = copyOf(mSignalStrength, mNumPhones);
         mMessageWaiting = copyOf(mMessageWaiting, mNumPhones);
         mCallForwarding = copyOf(mCallForwarding, mNumPhones);
-        mCellLocation = copyOf(mCellLocation, mNumPhones);
+        mCellIdentity = copyOf(mCellIdentity, mNumPhones);
         mSrvccState = copyOf(mSrvccState, mNumPhones);
         mPreciseCallState = copyOf(mPreciseCallState, mNumPhones);
         mForegroundCallState = copyOf(mForegroundCallState, mNumPhones);
@@ -439,31 +440,22 @@
             mUserMobileDataState[i] = false;
             mMessageWaiting[i] =  false;
             mCallForwarding[i] =  false;
-            mCellLocation[i] = new Bundle();
+            mCellIdentity[i] = null;
             mCellInfo.add(i, null);
             mImsReasonInfo.add(i, null);
             mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
             mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
             mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
             mCallQuality[i] = createCallQuality();
-            mCallAttributes[i] = new CallAttributes(new PreciseCallState(),
+            mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
                     TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
             mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-            mPreciseCallState[i] = new PreciseCallState();
+            mPreciseCallState[i] = createPreciseCallState();
             mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mPreciseDataConnectionStates.add(new HashMap<String, PreciseDataConnectionState>());
         }
-
-        // Note that location can be null for non-phone builds like
-        // like the generic one.
-        CellLocation  location = CellLocation.getEmpty();
-        if (location != null) {
-            for (int i = oldNumPhones; i < mNumPhones; i++) {
-                location.fillInNotifierBundle(mCellLocation[i]);
-            }
-        }
     }
 
     private void cutListToSize(List list, int size) {
@@ -503,7 +495,7 @@
         mSignalStrength = new SignalStrength[numPhones];
         mMessageWaiting = new boolean[numPhones];
         mCallForwarding = new boolean[numPhones];
-        mCellLocation = new Bundle[numPhones];
+        mCellIdentity = new CellIdentity[numPhones];
         mSrvccState = new int[numPhones];
         mPreciseCallState = new PreciseCallState[numPhones];
         mForegroundCallState = new int[numPhones];
@@ -532,31 +524,23 @@
             mUserMobileDataState[i] = false;
             mMessageWaiting[i] =  false;
             mCallForwarding[i] =  false;
-            mCellLocation[i] = new Bundle();
+            mCellIdentity[i] = null;
             mCellInfo.add(i, null);
             mImsReasonInfo.add(i, null);
             mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
             mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
             mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
             mCallQuality[i] = createCallQuality();
-            mCallAttributes[i] = new CallAttributes(new PreciseCallState(),
+            mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
                     TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
             mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-            mPreciseCallState[i] = new PreciseCallState();
+            mPreciseCallState[i] = createPreciseCallState();
             mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mPreciseDataConnectionStates.add(new HashMap<String, PreciseDataConnectionState>());
         }
 
-        // Note that location can be null for non-phone builds like
-        // like the generic one.
-        if (location != null) {
-            for (int i = 0; i < numPhones; i++) {
-                location.fillInNotifierBundle(mCellLocation[i]);
-            }
-        }
-
         mAppOps = mContext.getSystemService(AppOpsManager.class);
     }
 
@@ -837,11 +821,10 @@
                     }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
                         try {
-                            if (DBG_LOC) log("listen: mCellLocation = "
-                                    + mCellLocation[phoneId]);
+                            if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
                             if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                r.callback.onCellLocationChanged(
-                                        new Bundle(mCellLocation[phoneId]));
+                                // null will be translated to empty CellLocation object in client.
+                                r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
                             }
                         } catch (RemoteException ex) {
                             remove(r.binder);
@@ -1629,11 +1612,13 @@
         broadcastDataConnectionFailed(apnType, subId);
     }
 
-    public void notifyCellLocation(Bundle cellLocation) {
-         notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation);
+    @Override
+    public void notifyCellLocation(CellIdentity cellLocation) {
+        notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation);
     }
 
-    public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) {
+    @Override
+    public void notifyCellLocationForSubscriber(int subId, CellIdentity cellLocation) {
         log("notifyCellLocationForSubscriber: subId=" + subId
                 + " cellLocation=" + cellLocation);
         if (!checkNotifyPermission("notifyCellLocation()")) {
@@ -1646,7 +1631,7 @@
         int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
-                mCellLocation[phoneId] = cellLocation;
+                mCellIdentity[phoneId] = cellLocation;
                 for (Record r : mRecords) {
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
                             idMatch(r.subId, subId, phoneId) &&
@@ -1656,7 +1641,7 @@
                                 log("notifyCellLocation: cellLocation=" + cellLocation
                                         + " r=" + r);
                             }
-                            r.callback.onCellLocationChanged(new Bundle(cellLocation));
+                            r.callback.onCellLocationChanged(cellLocation);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -2093,7 +2078,7 @@
                 pw.println("mCallForwarding=" + mCallForwarding[i]);
                 pw.println("mDataActivity=" + mDataActivity[i]);
                 pw.println("mDataConnectionState=" + mDataConnectionState[i]);
-                pw.println("mCellLocation=" + mCellLocation[i]);
+                pw.println("mCellIdentity=" + mCellIdentity[i]);
                 pw.println("mCellInfo=" + mCellInfo.get(i));
                 pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i));
                 pw.println("mSrvccState=" + mSrvccState[i]);
@@ -2583,10 +2568,13 @@
 
         if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
             try {
-                if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
-                        + mCellLocation[phoneId]);
+                if (DBG_LOC) {
+                    log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
+                            + mCellIdentity[phoneId]);
+                }
                 if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                    r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+                    // null will be translated to empty CellLocation object in client.
+                    r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
                 }
             } catch (RemoteException ex) {
                 mRemoveList.add(r.binder);
@@ -2678,6 +2666,15 @@
         }
     }
 
+    /** Returns a new PreciseCallState object with default values. */
+    private static PreciseCallState createPreciseCallState() {
+        return new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
+            PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
+            PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
+            DisconnectCause.NOT_VALID,
+            PreciseDisconnectCause.NOT_VALID);
+    }
+
     /** Returns a new CallQuality object with default values. */
     private static CallQuality createCallQuality() {
         return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6dc49b7..d7a46fe 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7558,6 +7558,26 @@
         });
     }
 
+    @Override
+    public void appNotResponding(final String reason) {
+        final int callingPid = Binder.getCallingPid();
+
+        synchronized (mPidsSelfLocked) {
+            final ProcessRecord app = mPidsSelfLocked.get(callingPid);
+            if (app == null) {
+                throw new SecurityException("Unknown process: " + callingPid);
+            }
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    app.appNotResponding(
+                            null, app.info, null, null, false, "App requested: " + reason);
+                }
+            });
+        }
+    }
+
     public final void installSystemProviders() {
         List<ProviderInfo> providers;
         synchronized (this) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0b74840..9f23cdaf 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2335,7 +2335,7 @@
             } else {
                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
                 final int mode = switchOp.evalMode();
-                if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
+                if (mode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName);
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
index 3049522..d673ec8 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.incremental;
 
 import android.annotation.NonNull;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.DataLoaderManager;
 import android.content.pm.DataLoaderParamsParcel;
@@ -85,7 +86,8 @@
             DataLoaderParamsParcel params,
             IDataLoaderStatusListener listener) {
         Bundle dataLoaderParams = new Bundle();
-        dataLoaderParams.putCharSequence("packageName", params.packageName);
+        dataLoaderParams.putParcelable("componentName",
+                new ComponentName(params.packageName, params.className));
         dataLoaderParams.putParcelable("control", control);
         dataLoaderParams.putParcelable("params", params);
         DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
@@ -109,8 +111,7 @@
             return false;
         }
         try {
-            // TODO: fix file list
-            dataLoader.start(null);
+            dataLoader.start();
             return true;
         } catch (RemoteException ex) {
             return false;
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
index 6a8434a..a68f777 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -111,14 +112,14 @@
             pw.println("File names and sizes don't match.");
             return ERROR_DATA_LOADER_INIT;
         }
-        final DataLoaderParams params = new DataLoaderParams(
-                "", LOADER_PACKAGE_NAME, dataLoaderDynamicArgs);
+        final DataLoaderParams params = DataLoaderParams.forIncremental(
+                new ComponentName(LOADER_PACKAGE_NAME, ""), "", dataLoaderDynamicArgs);
         PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
                 PackageInstaller.SessionParams.MODE_FULL_INSTALL);
         sessionParams.installFlags |= PackageManager.INSTALL_ALL_USERS;
         // Replace existing if same package is already installed
         sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
-        sessionParams.setIncrementalParams(params);
+        sessionParams.setDataLoaderParams(params);
 
         try {
             int sessionId = packageInstaller.createSession(sessionParams);
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 39c1b85..5c4479a 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -36,6 +35,8 @@
 class AppIntegrityManagerServiceImpl {
     private static final String TAG = "AppIntegrityManagerServiceImpl";
 
+    private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
+
     private final Context mContext;
     private final Handler mHandler;
     private final PackageManagerInternal mPackageManagerInternal;
@@ -51,6 +52,11 @@
 
         IntentFilter integrityVerificationFilter = new IntentFilter();
         integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
+        try {
+            integrityVerificationFilter.addDataType(PACKAGE_MIME_TYPE);
+        } catch (IntentFilter.MalformedMimeTypeException e) {
+            throw new RuntimeException("Mime type malformed: should never happen.", e);
+        }
 
         mContext.registerReceiver(
                 new BroadcastReceiver() {
@@ -74,7 +80,8 @@
         int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1);
         // TODO: implement this method.
         Slog.i(TAG, "Received integrity verification intent " + intent.toString());
+        Slog.i(TAG, "Extras " + intent.getExtras());
         mPackageManagerInternal.setIntegrityVerificationResult(
-                verificationId, PackageManager.VERIFICATION_ALLOW);
+                verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
     }
 }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
index cfe50c6..ebf6a2e 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -16,6 +16,10 @@
 
 package com.android.server.integrity.serializer;
 
+import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
+import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
+import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;
+
 import android.content.integrity.AtomicFormula;
 import android.content.integrity.CompoundFormula;
 import android.content.integrity.Formula;
@@ -29,6 +33,7 @@
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
@@ -75,13 +80,32 @@
         }
     }
 
-    private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException {
-        xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG);
+    private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer)
+            throws RuleSerializeException {
+        try {
+            // Determine the indexing groups and the order of the rules within each indexed group.
+            Map<Integer, List<Rule>> indexedRules =
+                    RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules);
+
+            // Write the XML formatted rules in order.
+            xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG);
+
+            serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), xmlSerializer);
+            serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), xmlSerializer);
+            serializeRuleList(indexedRules.get(NOT_INDEXED), xmlSerializer);
+
+            xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG);
+            xmlSerializer.endDocument();
+        } catch (Exception e) {
+            throw new RuleSerializeException(e.getMessage(), e);
+        }
+    }
+
+    private void serializeRuleList(List<Rule> rules, XmlSerializer xmlSerializer)
+            throws IOException {
         for (Rule rule : rules) {
             serializeRule(rule, xmlSerializer);
         }
-        xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG);
-        xmlSerializer.endDocument();
     }
 
     private void serializeRule(Rule rule, XmlSerializer xmlSerializer) throws IOException {
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 0719797..0dfea7f 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -76,13 +76,12 @@
                     return false;
                 }
             }
-            CharSequence packageNameSeq = params.getCharSequence("packageName");
-            if (packageNameSeq == null) {
-                Slog.e(TAG, "Must specify package name.");
+            ComponentName componentName = params.getParcelable("componentName");
+            if (componentName == null) {
+                Slog.e(TAG, "Must specify component name.");
                 return false;
             }
-            String packageName = packageNameSeq.toString();
-            ComponentName dataLoaderComponent = getDataLoaderServiceName(packageName);
+            ComponentName dataLoaderComponent = resolveDataLoaderComponentName(componentName);
             if (dataLoaderComponent == null) {
                 return false;
             }
@@ -103,22 +102,23 @@
         /**
          * Find the ComponentName of the data loader service provider, given its package name.
          *
-         * @param packageName the package name of the provider.
+         * @param componentName the name of the provider.
          * @return ComponentName of the data loader service provider. Null if provider not found.
          */
-        private @Nullable ComponentName getDataLoaderServiceName(String packageName) {
+        private @Nullable ComponentName resolveDataLoaderComponentName(
+                ComponentName componentName) {
             final PackageManager pm = mContext.getPackageManager();
             if (pm == null) {
                 Slog.e(TAG, "PackageManager is not available.");
                 return null;
             }
             Intent intent = new Intent(Intent.ACTION_LOAD_DATA);
-            intent.setPackage(packageName);
+            intent.setComponent(componentName);
             List<ResolveInfo> services =
                     pm.queryIntentServicesAsUser(intent, 0, UserHandle.getCallingUserId());
             if (services == null || services.isEmpty()) {
                 Slog.e(TAG,
-                        "Failed to find data loader service provider in package " + packageName);
+                        "Failed to find data loader service provider in " + componentName);
                 return null;
             }
 
@@ -128,23 +128,21 @@
             int numServices = services.size();
             for (int i = 0; i < numServices; i++) {
                 ResolveInfo ri = services.get(i);
-                ComponentName componentName = new ComponentName(
+                ComponentName resolved = new ComponentName(
                         ri.serviceInfo.packageName, ri.serviceInfo.name);
                 // There should only be one matching provider inside the given package.
                 // If there's more than one, return the first one found.
                 try {
-                    ApplicationInfo ai = pm.getApplicationInfo(componentName.getPackageName(), 0);
+                    ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
                     if (checkLoader && !ai.isPrivilegedApp()) {
                         Slog.w(TAG,
-                                "Data loader: " + componentName.getPackageName()
-                                        + " is not a privileged app, skipping.");
+                                "Data loader: " + resolved + " is not a privileged app, skipping.");
                         continue;
                     }
-                    return componentName;
+                    return resolved;
                 } catch (PackageManager.NameNotFoundException ex) {
                     Slog.w(TAG,
-                            "Privileged data loader: " + componentName.getPackageName()
-                                    + " not found, skipping.");
+                            "Privileged data loader: " + resolved + " not found, skipping.");
                 }
 
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a54534b..47a41f5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -257,8 +257,9 @@
         }
         // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK
         // atomic install which needs to query sessions, which requires lock on mSessions.
+        boolean isDeviceUpgrading = mPm.isDeviceUpgrading();
         for (PackageInstallerSession session : stagedSessionsToRestore) {
-            if (mPm.isDeviceUpgrading() && !session.isStagedAndInTerminalState()) {
+            if (isDeviceUpgrading && !session.isStagedAndInTerminalState()) {
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                         "Build fingerprint has changed");
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c12395e..ac183dc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -16,6 +16,8 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.DataLoaderType.INCREMENTAL;
+import static android.content.pm.DataLoaderType.STREAMING;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -49,12 +51,18 @@
 import android.annotation.Nullable;
 import android.app.admin.DevicePolicyEventLogger;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.DataLoaderManager;
+import android.content.pm.DataLoaderParams;
+import android.content.pm.FileSystemControlParcel;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderStatusListener;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.IPackageInstallerSessionFileSystemConnector;
@@ -84,6 +92,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelableException;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.RevocableFileDescriptor;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -127,12 +136,12 @@
 import java.io.FileFilter;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
 public class PackageInstallerSession extends IPackageInstallerSession.Stub {
     private static final String TAG = "PackageInstallerSession";
@@ -189,7 +198,11 @@
     private static final String ATTR_VOLUME_UUID = "volumeUuid";
     private static final String ATTR_NAME = "name";
     private static final String ATTR_INSTALL_REASON = "installRason";
-    private static final String ATTR_DATA_LOADER_PACKAGE_NAME = "dataLoaderPackageName";
+    private static final String ATTR_IS_DATALOADER = "isDataLoader";
+    private static final String ATTR_DATALOADER_TYPE = "dataLoaderType";
+    private static final String ATTR_DATALOADER_PACKAGE_NAME = "dataLoaderPackageName";
+    private static final String ATTR_DATALOADER_CLASS_NAME = "dataLoaderClassName";
+    private static final String ATTR_DATALOADER_ARGUMENTS = "dataLoaderArguments";
     private static final String ATTR_LENGTH_BYTES = "lengthBytes";
     private static final String ATTR_METADATA = "metadata";
 
@@ -414,7 +427,15 @@
     };
 
     private boolean isDataLoaderInstallation() {
-        return !TextUtils.isEmpty(params.dataLoaderPackageName);
+        return params.dataLoaderParams != null;
+    }
+
+    private boolean isStreamingInstallation() {
+        return isDataLoaderInstallation() && params.dataLoaderParams.getType() == STREAMING;
+    }
+
+    private boolean isIncrementalInstallation() {
+        return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL;
     }
 
     /**
@@ -525,14 +546,13 @@
                 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
 
         // TODO(b/136132412): sanity check if session should not be incremental
-        if (!params.isStaged && params.incrementalParams != null
-                && !params.incrementalParams.getPackageName().isEmpty()) {
+        if (!params.isStaged && isIncrementalInstallation()) {
             IncrementalManager incrementalManager = (IncrementalManager) mContext.getSystemService(
                     Context.INCREMENTAL_SERVICE);
             if (incrementalManager != null) {
                 mIncrementalFileStorages =
                         new IncrementalFileStorages(mPackageName, stageDir, incrementalManager,
-                                params.incrementalParams);
+                                params.dataLoaderParams);
             }
         }
     }
@@ -714,7 +734,7 @@
     public void removeSplit(String splitName) {
         if (isDataLoaderInstallation()) {
             throw new IllegalStateException(
-                    "Cannot remove splits in a callback installation session.");
+                    "Cannot remove splits in a data loader installation session.");
         }
         if (TextUtils.isEmpty(params.appPackageName)) {
             throw new IllegalStateException("Must specify package name to remove a split");
@@ -753,7 +773,7 @@
     private void assertCanWrite(boolean reverseMode) {
         if (isDataLoaderInstallation()) {
             throw new IllegalStateException(
-                    "Cannot write regular files in a callback installation session.");
+                    "Cannot write regular files in a data loader installation session.");
         }
         synchronized (mLock) {
             assertCallerIsOwnerOrRootLocked();
@@ -894,7 +914,7 @@
     public ParcelFileDescriptor openRead(String name) {
         if (isDataLoaderInstallation()) {
             throw new IllegalStateException(
-                    "Cannot read regular files in a callback installation session.");
+                    "Cannot read regular files in a data loader installation session.");
         }
         synchronized (mLock) {
             assertCallerIsOwnerOrRootLocked();
@@ -1663,7 +1683,7 @@
                 computeProgressLocked(true);
 
                 // Unpack native libraries for non-incremental installation
-                if (params.incrementalParams == null) {
+                if (isIncrementalInstallation()) {
                     extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
                 }
             }
@@ -2382,7 +2402,7 @@
         }
         if (!isDataLoaderInstallation()) {
             throw new IllegalStateException(
-                    "Cannot add files to non-callback installation session.");
+                    "Cannot add files to non-data loader installation session.");
         }
         // Use installer provided name for now; we always rename later
         if (!FileUtils.isValidExtFilename(name)) {
@@ -2401,7 +2421,7 @@
     public void removeFile(String name) {
         if (!isDataLoaderInstallation()) {
             throw new IllegalStateException(
-                    "Cannot add files to non-callback installation session.");
+                    "Cannot add files to non-data loader installation session.");
         }
         if (TextUtils.isEmpty(params.appPackageName)) {
             throw new IllegalStateException("Must specify package name to remove a split");
@@ -2415,76 +2435,121 @@
         }
     }
 
+    static class Notificator {
+        private int mValue = 0;
+
+        void setValue(int value) {
+            synchronized (this) {
+                mValue = value;
+                this.notify();
+            }
+        }
+        int waitForValue() {
+            synchronized (this) {
+                while (mValue == 0) {
+                    try {
+                        this.wait();
+                    } catch (InterruptedException e) {
+                        // Happens if someone interrupts your thread.
+                    }
+                }
+                return mValue;
+            }
+        }
+    }
+
     /**
      * Makes sure files are present in staging location.
      */
     private void prepareDataLoader()
             throws PackageManagerException, StreamingException {
-        if (!isDataLoaderInstallation()) {
+        if (!isStreamingInstallation()) {
             return;
         }
 
         FileSystemConnector connector = new FileSystemConnector();
 
-        FileInfo[] addedFiles = mFiles.stream().filter(
-                file -> sAddedFilter.accept(new File(file.name))).toArray(FileInfo[]::new);
-        String[] removedFiles = mFiles.stream().filter(
+        List<InstallationFile> addedFiles = mFiles.stream().filter(
+                file -> sAddedFilter.accept(new File(file.name))).map(
+                    file -> new InstallationFile(
+                            file.name, file.lengthBytes, file.metadata)).collect(
+                Collectors.toList());
+        List<String> removedFiles = mFiles.stream().filter(
                 file -> sRemovedFilter.accept(new File(file.name))).map(
-                    file -> file.name.substring(0,
-                        file.name.length() - REMOVE_MARKER_EXTENSION.length())).toArray(
-                String[]::new);
+                    file -> file.name.substring(
+                            0, file.name.length() - REMOVE_MARKER_EXTENSION.length())).collect(
+                Collectors.toList());
 
-        DataLoader dataLoader = new DataLoader();
-        try {
-            dataLoader.onCreate(connector);
-
-            if (!dataLoader.onPrepareImage(addedFiles, removedFiles)) {
-                throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
-                        "Failed to prepare image.");
-            }
-        } catch (IOException e) {
-            throw new StreamingException(e);
-        } finally {
-            dataLoader.onDestroy();
-        }
-    }
-
-    static class DataLoader {
-        private ParcelFileDescriptor mInFd = null;
-        private FileSystemConnector mConnector = null;
-
-        void onCreate(FileSystemConnector connector) throws IOException {
-            mConnector = connector;
+        DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
+        if (dataLoaderManager == null) {
+            throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+                    "Failed to find data loader manager service");
         }
 
-        void onDestroy() {
-            IoUtils.closeQuietly(mInFd);
-        }
+        // TODO(b/146080380): make this code async.
+        final Notificator created = new Notificator();
+        final Notificator started = new Notificator();
+        final Notificator imageReady = new Notificator();
 
-        private static final String STDIN_PATH = "-";
-        boolean onPrepareImage(FileInfo[] addedFiles, String[] removedFiles) throws IOException {
-            for (FileInfo fileInfo : addedFiles) {
-                String filePath = new String(fileInfo.metadata, StandardCharsets.UTF_8);
-                if (STDIN_PATH.equals(filePath) || TextUtils.isEmpty(filePath)) {
-                    if (mInFd == null) {
-                        Slog.e(TAG, "Invalid stdin file descriptor.");
-                        return false;
+        IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() {
+            @Override
+            public void onStatusChanged(int dataLoaderId, int status) {
+                switch (status) {
+                    case IDataLoaderStatusListener.DATA_LOADER_CREATED: {
+                        created.setValue(1);
+                        break;
                     }
-                    ParcelFileDescriptor inFd = ParcelFileDescriptor.dup(mInFd.getFileDescriptor());
-                    mConnector.writeData(fileInfo.name, 0, fileInfo.lengthBytes, inFd);
-                } else {
-                    File localFile = new File(filePath);
-                    ParcelFileDescriptor incomingFd = null;
-                    try {
-                        incomingFd = ParcelFileDescriptor.open(localFile,
-                                ParcelFileDescriptor.MODE_READ_ONLY);
-                        mConnector.writeData(fileInfo.name, 0, localFile.length(), incomingFd);
-                    } finally {
-                        IoUtils.closeQuietly(incomingFd);
+                    case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
+                        started.setValue(1);
+                        break;
+                    }
+                    case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: {
+                        imageReady.setValue(1);
+                        break;
+                    }
+                    case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
+                        imageReady.setValue(2);
+                        break;
                     }
                 }
             }
-            return true;
+        };
+
+        final DataLoaderParams params = this.params.dataLoaderParams;
+
+        final FileSystemControlParcel control = new FileSystemControlParcel();
+        control.callback = connector;
+
+        Bundle dataLoaderParams = new Bundle();
+        dataLoaderParams.putParcelable("componentName", params.getComponentName());
+        dataLoaderParams.putParcelable("control", control);
+        dataLoaderParams.putParcelable("params", params.getData());
+
+        if (!dataLoaderManager.initializeDataLoader(sessionId, dataLoaderParams, listener)) {
+            throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+                    "Failed to initialize data loader");
+        }
+        created.waitForValue();
+
+        IDataLoader dataLoader = dataLoaderManager.getDataLoader(sessionId);
+        if (dataLoader == null) {
+            throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+                    "Failure to obtain data loader");
+        }
+
+        try {
+            dataLoader.start();
+            started.waitForValue();
+
+            dataLoader.prepareImage(addedFiles, removedFiles);
+            if (imageReady.waitForValue() == 2) {
+                throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+                        "Failed to prepare image.");
+            }
+
+            dataLoader.destroy();
+        } catch (RemoteException e) {
+            throw new StreamingException(e);
         }
     }
 
@@ -2846,7 +2911,17 @@
             writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
             writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
 
-            writeStringAttribute(out, ATTR_DATA_LOADER_PACKAGE_NAME, params.dataLoaderPackageName);
+            final boolean isDataLoader = params.dataLoaderParams != null;
+            writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
+            if (isDataLoader) {
+                writeIntAttribute(out, ATTR_DATALOADER_TYPE, params.dataLoaderParams.getType());
+                writeStringAttribute(out, ATTR_DATALOADER_PACKAGE_NAME,
+                        params.dataLoaderParams.getComponentName().getPackageName());
+                writeStringAttribute(out, ATTR_DATALOADER_CLASS_NAME,
+                        params.dataLoaderParams.getComponentName().getClassName());
+                writeStringAttribute(out, ATTR_DATALOADER_ARGUMENTS,
+                        params.dataLoaderParams.getArguments());
+            }
 
             writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
             writeWhitelistedRestrictedPermissionsLocked(out,
@@ -2957,7 +3032,15 @@
         params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
         params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
 
-        params.dataLoaderPackageName = readStringAttribute(in, ATTR_DATA_LOADER_PACKAGE_NAME);
+        if (readBooleanAttribute(in, ATTR_IS_DATALOADER)) {
+            params.dataLoaderParams = new DataLoaderParams(
+                    readIntAttribute(in, ATTR_DATALOADER_TYPE),
+                    new ComponentName(
+                            readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME),
+                            readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)),
+                    readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS),
+                    null);
+        }
 
         final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
         if (appIconFile.exists()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index da104ee..785ca7d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -27,6 +27,8 @@
 import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_DEFAULT;
 import static android.content.Intent.CATEGORY_HOME;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_VERSION_CODE;
 import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
 import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -34,6 +36,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
@@ -558,6 +561,11 @@
     private static final boolean DEFAULT_VERIFY_ENABLE = true;
 
     /**
+     * Whether integrity verification is enabled by default.
+     */
+    private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
+
+    /**
      * The default maximum time to wait for the verification agent to return in
      * milliseconds.
      */
@@ -1444,6 +1452,7 @@
     static final int DEFERRED_NO_KILL_POST_DELETE = 23;
     static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24;
     static final int INTEGRITY_VERIFICATION_COMPLETE = 25;
+    static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26;
 
     static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
     static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
@@ -1707,13 +1716,13 @@
                     final int verificationId = msg.arg1;
                     final PackageVerificationState state = mPendingVerification.get(verificationId);
 
-                    if ((state != null) && !state.timeoutExtended()) {
+                    if ((state != null) && !state.isVerificationComplete()
+                            && !state.timeoutExtended()) {
                         final InstallParams params = state.getInstallParams();
                         final InstallArgs args = params.mArgs;
                         final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
 
                         Slog.i(TAG, "Verification timed out for " + originUri);
-                        mPendingVerification.remove(verificationId);
 
                         final UserHandle user = args.getUser();
                         if (getDefaultVerificationResponse(user)
@@ -1728,11 +1737,54 @@
                                     PackageManager.VERIFICATION_REJECT, user);
                             params.setReturnCode(
                                     PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
+                            state.setVerifierResponse(Binder.getCallingUid(),
+                                    PackageManager.VERIFICATION_REJECT);
+                        }
+
+                        if (state.areAllVerificationsComplete()) {
+                            mPendingVerification.remove(verificationId);
                         }
 
                         Trace.asyncTraceEnd(
                                 TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
                         params.handleVerificationFinished();
+
+                    }
+                    break;
+                }
+                case CHECK_PENDING_INTEGRITY_VERIFICATION: {
+                    final int verificationId = msg.arg1;
+                    final PackageVerificationState state = mPendingVerification.get(verificationId);
+
+                    if (state != null && !state.isIntegrityVerificationComplete()) {
+                        final InstallParams params = state.getInstallParams();
+                        final InstallArgs args = params.mArgs;
+                        final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
+
+                        Slog.i(TAG, "Integrity verification timed out for " + originUri);
+
+                        state.setIntegrityVerificationResult(
+                                getDefaultIntegrityVerificationResponse());
+
+                        if (getDefaultIntegrityVerificationResponse()
+                                == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
+                            Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
+                        } else {
+                            params.setReturnCode(
+                                    PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
+                        }
+
+                        if (state.areAllVerificationsComplete()) {
+                            mPendingVerification.remove(verificationId);
+                        }
+
+                        Trace.asyncTraceEnd(
+                                TRACE_TAG_PACKAGE_MANAGER,
+                                "integrity_verification",
+                                verificationId);
+
+                        params.handleIntegrityVerificationFinished();
                     }
                     break;
                 }
@@ -1741,7 +1793,9 @@
 
                     final PackageVerificationState state = mPendingVerification.get(verificationId);
                     if (state == null) {
-                        Slog.w(TAG, "Invalid verification token " + verificationId + " received");
+                        Slog.w(TAG, "Verification with id " + verificationId
+                                + " not found."
+                                + " It may be invalid or overridden by integrity verification");
                         break;
                     }
 
@@ -1750,8 +1804,6 @@
                     state.setVerifierResponse(response.callerUid, response.code);
 
                     if (state.isVerificationComplete()) {
-                        mPendingVerification.remove(verificationId);
-
                         final InstallParams params = state.getInstallParams();
                         final InstallArgs args = params.mArgs;
                         final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
@@ -1764,6 +1816,10 @@
                                     PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
                         }
 
+                        if (state.areAllVerificationsComplete()) {
+                            mPendingVerification.remove(verificationId);
+                        }
+
                         Trace.asyncTraceEnd(
                                 TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
 
@@ -1773,7 +1829,40 @@
                     break;
                 }
                 case INTEGRITY_VERIFICATION_COMPLETE: {
-                    // TODO: implement this case.
+                    final int verificationId = msg.arg1;
+
+                    final PackageVerificationState state = mPendingVerification.get(verificationId);
+                    if (state == null) {
+                        Slog.w(TAG, "Integrity verification with id " + verificationId
+                                + " not found. It may be invalid or overridden by verifier");
+                        break;
+                    }
+
+                    final int response = (Integer) msg.obj;
+
+                    final InstallParams params = state.getInstallParams();
+                    final InstallArgs args = params.mArgs;
+                    final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
+
+                    state.setIntegrityVerificationResult(response);
+
+                    if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
+                        Slog.i(TAG, "Integrity check passed for " + originUri);
+                    } else {
+                        params.setReturnCode(
+                                PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
+                    }
+
+                    if (state.areAllVerificationsComplete()) {
+                        mPendingVerification.remove(verificationId);
+                    }
+
+                    Trace.asyncTraceEnd(
+                            TRACE_TAG_PACKAGE_MANAGER,
+                            "integrity_verification",
+                            verificationId);
+
+                    params.handleIntegrityVerificationFinished();
                     break;
                 }
                 case START_INTENT_FILTER_VERIFICATIONS: {
@@ -13099,6 +13188,15 @@
     }
 
     /**
+     * Get the default integrity verification response code.
+     */
+    private int getDefaultIntegrityVerificationResponse() {
+        // We are not exposing this as a user-configurable setting because we don't want to provide
+        // an easy way to get around the integrity check.
+        return PackageManager.VERIFICATION_REJECT;
+    }
+
+    /**
      * Check whether or not package verification has been enabled.
      *
      * @return true if verification should be performed
@@ -13141,6 +13239,15 @@
         }
     }
 
+    /**
+     * Check whether or not integrity verification has been enabled.
+     */
+    private boolean isIntegrityVerificationEnabled() {
+        // We are not exposing this as a user-configurable setting because we don't want to provide
+        // an easy way to get around the integrity check.
+        return DEFAULT_INTEGRITY_VERIFY_ENABLE;
+    }
+
     @Override
     public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains)
             throws RemoteException {
@@ -13851,6 +13958,7 @@
         @NonNull final InstallSource installSource;
         final String volumeUuid;
         private boolean mVerificationCompleted;
+        private boolean mIntegrityVerificationCompleted;
         private boolean mEnableRollbackCompleted;
         private InstallArgs mArgs;
         int mRet;
@@ -14112,155 +14220,30 @@
 
             final InstallArgs args = createInstallArgs(this);
             mVerificationCompleted = true;
+            mIntegrityVerificationCompleted = true;
             mEnableRollbackCompleted = true;
             mArgs = args;
 
             if (ret == PackageManager.INSTALL_SUCCEEDED) {
-                // TODO: http://b/22976637
-                // Apps installed for "all" users use the device owner to verify the app
-                UserHandle verifierUser = getUser();
-                if (verifierUser == UserHandle.ALL) {
-                    verifierUser = UserHandle.SYSTEM;
-                }
+                final int verificationId = mPendingVerificationToken++;
 
-                /*
-                 * Determine if we have any installed package verifiers. If we
-                 * do, then we'll defer to them to verify the packages.
-                 */
-                final int requiredUid = mRequiredVerifierPackage == null ? -1
-                        : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
-                                verifierUser.getIdentifier());
-                final int installerUid =
-                        verificationInfo == null ? -1 : verificationInfo.installerUid;
-                if (!origin.existing && requiredUid != -1
-                        && isVerificationEnabled(
-                                verifierUser.getIdentifier(), installFlags, installerUid)) {
-                    final Intent verification = new Intent(
-                            Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
-                    verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                    verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
-                            PACKAGE_MIME_TYPE);
-                    verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-                    // Query all live verifiers based on current user state
-                    final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
-                            PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
-                            false /*allowDynamicSplits*/);
-
-                    if (DEBUG_VERIFY) {
-                        Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
-                                + verification.toString() + " with " + pkgLite.verifiers.length
-                                + " optional verifiers");
-                    }
-
-                    final int verificationId = mPendingVerificationToken++;
-
-                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
-
-                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
-                            installSource.initiatingPackageName);
-
-                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
-                            installFlags);
-
-                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
-                            pkgLite.packageName);
-
-                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
-                            pkgLite.versionCode);
-
-                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
-                            pkgLite.getLongVersionCode());
-
-                    if (verificationInfo != null) {
-                        if (verificationInfo.originatingUri != null) {
-                            verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
-                                    verificationInfo.originatingUri);
-                        }
-                        if (verificationInfo.referrer != null) {
-                            verification.putExtra(Intent.EXTRA_REFERRER,
-                                    verificationInfo.referrer);
-                        }
-                        if (verificationInfo.originatingUid >= 0) {
-                            verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
-                                    verificationInfo.originatingUid);
-                        }
-                        if (verificationInfo.installerUid >= 0) {
-                            verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
-                                    verificationInfo.installerUid);
-                        }
-                    }
-
-                    final PackageVerificationState verificationState = new PackageVerificationState(
-                            requiredUid, this);
-
+                // Perform package verification (unless we are simply moving the package).
+                if (!origin.existing) {
+                    PackageVerificationState verificationState =
+                            new PackageVerificationState(this);
                     mPendingVerification.append(verificationId, verificationState);
 
-                    final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
-                            receivers, verificationState);
+                    sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
+                    ret = sendPackageVerificationRequest(
+                            verificationId, pkgLite, verificationState);
 
-                    DeviceIdleInternal idleController =
-                            mInjector.getLocalDeviceIdleController();
-                    final long idleDuration = getVerificationTimeout();
-
-                    /*
-                     * If any sufficient verifiers were listed in the package
-                     * manifest, attempt to ask them.
-                     */
-                    if (sufficientVerifiers != null) {
-                        final int N = sufficientVerifiers.size();
-                        if (N == 0) {
-                            Slog.i(TAG, "Additional verifiers required, but none installed.");
-                            ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
-                        } else {
-                            for (int i = 0; i < N; i++) {
-                                final ComponentName verifierComponent = sufficientVerifiers.get(i);
-                                idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
-                                        verifierComponent.getPackageName(), idleDuration,
-                                        verifierUser.getIdentifier(), false, "package verifier");
-
-                                final Intent sufficientIntent = new Intent(verification);
-                                sufficientIntent.setComponent(verifierComponent);
-                                mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
-                            }
-                        }
-                    }
-
-                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
-                            mRequiredVerifierPackage, receivers);
-                    if (ret == PackageManager.INSTALL_SUCCEEDED
-                            && mRequiredVerifierPackage != null) {
-                        Trace.asyncTraceBegin(
-                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-                        /*
-                         * Send the intent to the required verification agent,
-                         * but only start the verification timeout after the
-                         * target BroadcastReceivers have run.
-                         */
-                        verification.setComponent(requiredVerifierComponent);
-                        idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
-                                mRequiredVerifierPackage, idleDuration,
-                                verifierUser.getIdentifier(), false, "package verifier");
-                        mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
-                                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
-                                new BroadcastReceiver() {
-                                    @Override
-                                    public void onReceive(Context context, Intent intent) {
-                                        final Message msg = mHandler
-                                                .obtainMessage(CHECK_PENDING_VERIFICATION);
-                                        msg.arg1 = verificationId;
-                                        mHandler.sendMessageDelayed(msg, getVerificationTimeout());
-                                    }
-                                }, null, 0, null, null);
-
-                        /*
-                         * We don't want the copy to proceed until verification
-                         * succeeds.
-                         */
-                        mVerificationCompleted = false;
+                    // If both verifications are skipped, we should remove the state.
+                    if (verificationState.areAllVerificationsComplete()) {
+                        mPendingVerification.remove(verificationId);
                     }
                 }
 
+
                 if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                     // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
                     final int enableRollbackToken = mPendingEnableRollbackToken++;
@@ -14316,6 +14299,228 @@
             mRet = ret;
         }
 
+        /**
+         * Send a request to check the integrity of the package.
+         */
+        void sendIntegrityVerificationRequest(
+                int verificationId,
+                PackageInfoLite pkgLite,
+                PackageVerificationState verificationState) {
+            if (!isIntegrityVerificationEnabled()) {
+                // Consider the integrity check as passed.
+                verificationState.setIntegrityVerificationResult(
+                        PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+                return;
+            }
+
+            final Intent integrityVerification =
+                    new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
+
+            integrityVerification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
+                    PACKAGE_MIME_TYPE);
+
+            final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    | Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                    | Intent.FLAG_RECEIVER_FOREGROUND;
+            integrityVerification.addFlags(flags);
+
+            integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId);
+            integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName);
+            integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode);
+            populateInstallerExtras(integrityVerification);
+
+            // send to integrity component only.
+            integrityVerification.setPackage("android");
+
+            DeviceIdleInternal idleController =
+                    mInjector.getLocalDeviceIdleController();
+            final long idleDuration = getVerificationTimeout();
+
+            idleController.addPowerSaveTempWhitelistAppDirect(Process.myUid(),
+                     idleDuration,
+                    false, "integrity component");
+            mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM,
+                    /* receiverPermission= */ null,
+                    new BroadcastReceiver() {
+                        @Override
+                        public void onReceive(Context context, Intent intent) {
+                            final Message msg =
+                                    mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
+                            msg.arg1 = verificationId;
+                            // TODO: do we want to use the same timeout?
+                            mHandler.sendMessageDelayed(msg, getVerificationTimeout());
+                        }
+                    }, /* scheduler= */ null,
+                    /* initialCode= */ 0,
+                    /* initialData= */ null,
+                    /* initialExtras= */ null);
+
+            Trace.asyncTraceBegin(
+                    TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId);
+
+            // stop the copy until verification succeeds.
+            mIntegrityVerificationCompleted = false;
+        }
+
+        /**
+         * Send a request to verifier(s) to verify the package if necessary, and return
+         * {@link PackageManager#INSTALL_SUCCEEDED} if succeeded.
+         */
+        int sendPackageVerificationRequest(
+                int verificationId,
+                PackageInfoLite pkgLite,
+                PackageVerificationState verificationState) {
+            int ret = INSTALL_SUCCEEDED;
+
+            // TODO: http://b/22976637
+            // Apps installed for "all" users use the device owner to verify the app
+            UserHandle verifierUser = getUser();
+            if (verifierUser == UserHandle.ALL) {
+                verifierUser = UserHandle.SYSTEM;
+            }
+
+            /*
+             * Determine if we have any installed package verifiers. If we
+             * do, then we'll defer to them to verify the packages.
+             */
+            final int requiredUid = mRequiredVerifierPackage == null ? -1
+                    : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+                            verifierUser.getIdentifier());
+            verificationState.setRequiredVerifierUid(requiredUid);
+            final int installerUid =
+                    verificationInfo == null ? -1 : verificationInfo.installerUid;
+            if (!origin.existing && requiredUid != -1
+                    && isVerificationEnabled(
+                    verifierUser.getIdentifier(), installFlags, installerUid)) {
+                final Intent verification = new Intent(
+                        Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
+                verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
+                        PACKAGE_MIME_TYPE);
+                verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+                // Query all live verifiers based on current user state
+                final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
+                        PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
+                        false /*allowDynamicSplits*/);
+
+                if (DEBUG_VERIFY) {
+                    Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
+                            + verification.toString() + " with " + pkgLite.verifiers.length
+                            + " optional verifiers");
+                }
+
+                verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
+
+                verification.putExtra(
+                        PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, installFlags);
+
+                verification.putExtra(
+                        PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
+
+                verification.putExtra(
+                        PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode);
+
+                verification.putExtra(
+                        PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
+                        pkgLite.getLongVersionCode());
+
+                populateInstallerExtras(verification);
+
+                final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
+                        receivers, verificationState);
+
+                DeviceIdleInternal idleController =
+                        mInjector.getLocalDeviceIdleController();
+                final long idleDuration = getVerificationTimeout();
+
+                /*
+                 * If any sufficient verifiers were listed in the package
+                 * manifest, attempt to ask them.
+                 */
+                if (sufficientVerifiers != null) {
+                    final int n = sufficientVerifiers.size();
+                    if (n == 0) {
+                        Slog.i(TAG, "Additional verifiers required, but none installed.");
+                        ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
+                    } else {
+                        for (int i = 0; i < n; i++) {
+                            final ComponentName verifierComponent = sufficientVerifiers.get(i);
+                            idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
+                                    verifierComponent.getPackageName(), idleDuration,
+                                    verifierUser.getIdentifier(), false, "package verifier");
+
+                            final Intent sufficientIntent = new Intent(verification);
+                            sufficientIntent.setComponent(verifierComponent);
+                            mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
+                        }
+                    }
+                }
+
+                final ComponentName requiredVerifierComponent = matchComponentForVerifier(
+                        mRequiredVerifierPackage, receivers);
+                if (mRequiredVerifierPackage != null) {
+                    /*
+                     * Send the intent to the required verification agent,
+                     * but only start the verification timeout after the
+                     * target BroadcastReceivers have run.
+                     */
+                    verification.setComponent(requiredVerifierComponent);
+                    idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
+                            mRequiredVerifierPackage, idleDuration,
+                            verifierUser.getIdentifier(), false, "package verifier");
+                    mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
+                            android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+                            new BroadcastReceiver() {
+                                @Override
+                                public void onReceive(Context context, Intent intent) {
+                                    final Message msg = mHandler
+                                            .obtainMessage(CHECK_PENDING_VERIFICATION);
+                                    msg.arg1 = verificationId;
+                                    mHandler.sendMessageDelayed(msg, getVerificationTimeout());
+                                }
+                            }, null, 0, null, null);
+
+                    Trace.asyncTraceBegin(
+                            TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
+                    /*
+                     * We don't want the copy to proceed until verification
+                     * succeeds.
+                     */
+                    mVerificationCompleted = false;
+                }
+            } else {
+                verificationState.setVerifierResponse(
+                        requiredUid, PackageManager.VERIFICATION_ALLOW);
+            }
+            return ret;
+        }
+
+        void populateInstallerExtras(Intent intent) {
+            intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
+                    installSource.initiatingPackageName);
+
+            if (verificationInfo != null) {
+                if (verificationInfo.originatingUri != null) {
+                    intent.putExtra(Intent.EXTRA_ORIGINATING_URI,
+                            verificationInfo.originatingUri);
+                }
+                if (verificationInfo.referrer != null) {
+                    intent.putExtra(Intent.EXTRA_REFERRER,
+                            verificationInfo.referrer);
+                }
+                if (verificationInfo.originatingUid >= 0) {
+                    intent.putExtra(Intent.EXTRA_ORIGINATING_UID,
+                            verificationInfo.originatingUid);
+                }
+                if (verificationInfo.installerUid >= 0) {
+                    intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
+                            verificationInfo.installerUid);
+                }
+            }
+        }
+
         void setReturnCode(int ret) {
             if (mRet == PackageManager.INSTALL_SUCCEEDED) {
                 // Only update mRet if it was previously INSTALL_SUCCEEDED to
@@ -14325,10 +14530,28 @@
         }
 
         void handleVerificationFinished() {
-            mVerificationCompleted = true;
-            handleReturnCode();
+            if (!mVerificationCompleted) {
+                mVerificationCompleted = true;
+                if (mIntegrityVerificationCompleted || mRet != INSTALL_SUCCEEDED) {
+                    mIntegrityVerificationCompleted = true;
+                    handleReturnCode();
+                }
+                // integrity verification still pending.
+            }
         }
 
+        void handleIntegrityVerificationFinished() {
+            if (!mIntegrityVerificationCompleted) {
+                mIntegrityVerificationCompleted = true;
+                if (mVerificationCompleted || mRet != INSTALL_SUCCEEDED) {
+                    mVerificationCompleted = true;
+                    handleReturnCode();
+                }
+                // verifier still pending
+            }
+        }
+
+
         void handleRollbackEnabled() {
             // TODO(ruhler) b/112431924: Consider halting the install if we
             // couldn't enable rollback.
@@ -14338,7 +14561,8 @@
 
         @Override
         void handleReturnCode() {
-            if (mVerificationCompleted && mEnableRollbackCompleted) {
+            if (mVerificationCompleted
+                    && mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
                 if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
                     String packageName = "";
                     try {
@@ -22673,7 +22897,6 @@
                 if (ps != null) {
                     return ps.getCeDataInode(userId);
                 }
-                Slog.e(TAG, "failed to find package " + packageName);
                 return 0;
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index dfffbd6..10e2780 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -34,6 +34,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.DataLoaderParams;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageInstaller;
@@ -136,7 +137,9 @@
     private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
     private static final int DEFAULT_WAIT_MS = 60 * 1000;
 
-    private static final String PM_SHELL_DATALOADER = "com.android.pm.dataloader";
+    private static final String DATA_LOADER_PACKAGE = "android";
+    private static final String DATA_LOADER_CLASS =
+            "com.android.server.pm.PackageManagerShellCommandDataLoader";
 
     final IPackageManager mInterface;
     final IPermissionManager mPermissionManager;
@@ -1159,8 +1162,10 @@
 
     private int runStreamingInstall() throws RemoteException {
         final InstallParams params = makeInstallParams();
-        if (TextUtils.isEmpty(params.sessionParams.dataLoaderPackageName)) {
-            params.sessionParams.setDataLoaderPackageName(PM_SHELL_DATALOADER);
+        if (params.sessionParams.dataLoaderParams == null) {
+            final DataLoaderParams dataLoaderParams = DataLoaderParams.forStreaming(
+                    new ComponentName(DATA_LOADER_PACKAGE, DATA_LOADER_CLASS), "");
+            params.sessionParams.setDataLoaderParams(dataLoaderParams);
         }
         return doRunInstall(params);
     }
@@ -1171,7 +1176,7 @@
 
     private int doRunInstall(final InstallParams params) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        final boolean streaming = !TextUtils.isEmpty(params.sessionParams.dataLoaderPackageName);
+        final boolean streaming = params.sessionParams.dataLoaderParams != null;
 
         ArrayList<String> inPaths = getRemainingArgs();
         if (inPaths.isEmpty()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
new file mode 100644
index 0000000..1ee9ab8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.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.server.pm;
+
+import android.annotation.NonNull;
+import android.content.pm.DataLoaderParams;
+import android.content.pm.InstallationFile;
+import android.os.ParcelFileDescriptor;
+import android.service.dataloader.DataLoaderService;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+
+/**
+ * Callback data loader for PackageManagerShellCommand installations.
+ */
+public class PackageManagerShellCommandDataLoader extends DataLoaderService {
+    public static final String TAG = "PackageManagerShellCommandDataLoader";
+
+    static class DataLoader implements DataLoaderService.DataLoader {
+        private ParcelFileDescriptor mInFd = null;
+        private FileSystemConnector mConnector = null;
+
+        private static final String STDIN_PATH = "-";
+
+        @Override
+        public boolean onCreate(@NonNull DataLoaderParams dataLoaderParams,
+                @NonNull FileSystemConnector connector) {
+            mConnector = connector;
+            return true;
+        }
+        @Override
+        public boolean onPrepareImage(Collection<InstallationFile> addedFiles,
+                Collection<String> removedFiles) {
+            try {
+                for (InstallationFile fileInfo : addedFiles) {
+                    String filePath = new String(fileInfo.getMetadata(), StandardCharsets.UTF_8);
+                    if (STDIN_PATH.equals(filePath) || TextUtils.isEmpty(filePath)) {
+                        // TODO(b/146080380): add support for STDIN installations.
+                        if (mInFd == null) {
+                            Slog.e(TAG, "Invalid stdin file descriptor.");
+                            return false;
+                        }
+                        ParcelFileDescriptor inFd = ParcelFileDescriptor.dup(
+                                mInFd.getFileDescriptor());
+                        mConnector.writeData(fileInfo.getName(), 0, fileInfo.getSize(), inFd);
+                    } else {
+                        File localFile = new File(filePath);
+                        ParcelFileDescriptor incomingFd = null;
+                        try {
+                            // TODO(b/146080380): open files via callback into shell command.
+                            incomingFd = ParcelFileDescriptor.open(localFile,
+                                    ParcelFileDescriptor.MODE_READ_ONLY);
+                            mConnector.writeData(fileInfo.getName(), 0, localFile.length(),
+                                    incomingFd);
+                        } finally {
+                            IoUtils.closeQuietly(incomingFd);
+                        }
+                    }
+                }
+                return true;
+            } catch (IOException e) {
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public DataLoaderService.DataLoader onCreateDataLoader() {
+        return new DataLoader();
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index c50bf59..ea7af90 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -22,18 +22,17 @@
 import com.android.server.pm.PackageManagerService.InstallParams;
 
 /**
- * Tracks the package verification state for a particular package. Each package
- * verification has a required verifier and zero or more sufficient verifiers.
- * Only one of the sufficient verifier list must return affirmative to allow the
- * package to be considered verified. If there are zero sufficient verifiers,
- * then package verification is considered complete.
+ * Tracks the package verification state for a particular package. Each package verification has a
+ * required verifier and zero or more sufficient verifiers. Only one of the sufficient verifier list
+ * must return affirmative to allow the package to be considered verified. If there are zero
+ * sufficient verifiers, then package verification is considered complete.
  */
 class PackageVerificationState {
     private final InstallParams mParams;
 
     private final SparseBooleanArray mSufficientVerifierUids;
 
-    private final int mRequiredVerifierUid;
+    private int mRequiredVerifierUid;
 
     private boolean mSufficientVerificationComplete;
 
@@ -45,16 +44,13 @@
 
     private boolean mExtendedTimeout;
 
+    private boolean mIntegrityVerificationComplete;
+
     /**
-     * Create a new package verification state where {@code requiredVerifierUid}
-     * is the user ID for the package that must reply affirmative before things
-     * can continue.
-     *
-     * @param requiredVerifierUid user ID of required package verifier
-     * @param args
+     * Create a new package verification state where {@code requiredVerifierUid} is the user ID for
+     * the package that must reply affirmative before things can continue.
      */
-    PackageVerificationState(int requiredVerifierUid, InstallParams params) {
-        mRequiredVerifierUid = requiredVerifierUid;
+    PackageVerificationState(InstallParams params) {
         mParams = params;
         mSufficientVerifierUids = new SparseBooleanArray();
         mExtendedTimeout = false;
@@ -64,6 +60,11 @@
         return mParams;
     }
 
+    /** Sets the user ID of the required package verifier. */
+    void setRequiredVerifierUid(int uid) {
+        mRequiredVerifierUid = uid;
+    }
+
     /**
      * Add a verifier which is added to our sufficient list.
      *
@@ -74,8 +75,8 @@
     }
 
     /**
-     * Should be called when a verification is received from an agent so the
-     * state of the package verification can be tracked.
+     * Should be called when a verification is received from an agent so the state of the package
+     * verification can be tracked.
      *
      * @param uid user ID of the verifying agent
      * @return {@code true} if the verifying agent actually exists in our list
@@ -114,9 +115,8 @@
     }
 
     /**
-     * Returns whether verification is considered complete. This means that the
-     * required verifier and at least one of the sufficient verifiers has
-     * returned a positive verification.
+     * Returns whether verification is considered complete. This means that the required verifier
+     * and at least one of the sufficient verifiers has returned a positive verification.
      *
      * @return {@code true} when verification is considered complete
      */
@@ -133,8 +133,8 @@
     }
 
     /**
-     * Returns whether installation should be allowed. This should only be
-     * called after {@link #isVerificationComplete()} returns {@code true}.
+     * Returns whether installation should be allowed. This should only be called after {@link
+     * #isVerificationComplete()} returns {@code true}.
      *
      * @return {@code true} if installation should be allowed
      */
@@ -150,9 +150,7 @@
         return true;
     }
 
-    /**
-     * Extend the timeout for this Package to be verified.
-     */
+    /** Extend the timeout for this Package to be verified. */
     void extendTimeout() {
         if (!mExtendedTimeout) {
             mExtendedTimeout = true;
@@ -167,4 +165,16 @@
     boolean timeoutExtended() {
         return mExtendedTimeout;
     }
+
+    void setIntegrityVerificationResult(int code) {
+        mIntegrityVerificationComplete = true;
+    }
+
+    boolean isIntegrityVerificationComplete() {
+        return mIntegrityVerificationComplete;
+    }
+
+    boolean areAllVerificationsComplete() {
+        return mIntegrityVerificationComplete && isVerificationComplete();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1503282..834e924 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6308,6 +6308,11 @@
             resolveSizeCompatModeConfiguration(newParentConfiguration);
         } else {
             super.resolveOverrideConfiguration(newParentConfiguration);
+            // We ignore activities' requested orientation in multi-window modes. Task level may
+            // take them into consideration when calculating bounds.
+            if (getParent() != null && getParent().inMultiWindowMode()) {
+                resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
+            }
             applyAspectRatio(resolvedConfig.windowConfiguration.getBounds(),
                     newParentConfiguration.windowConfiguration.getAppBounds(),
                     newParentConfiguration.windowConfiguration.getBounds());
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index be3a613..1355424 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -252,7 +252,8 @@
         final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
                 suspendingPackage, mUserId);
         mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
-                suspendingPackage, dialogInfo, mUserId);
+                suspendingPackage, dialogInfo, deferCrossProfileAppsAnimationIfNecessary(),
+                mUserId);
         mCallingPid = mRealCallingPid;
         mCallingUid = mRealCallingUid;
         mResolvedType = null;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index fd95ac5..45c012e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1881,7 +1881,10 @@
 
         if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
                 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-            if (insideParentBounds && mStack != null) {
+            if (insideParentBounds && WindowConfiguration.isFloating(windowingMode)) {
+                mTmpNonDecorBounds.set(mTmpFullBounds);
+                mTmpStableBounds.set(mTmpFullBounds);
+            } else if (insideParentBounds && mStack != null) {
                 final DisplayInfo di = new DisplayInfo();
                 mStack.getDisplay().mDisplay.getDisplayInfo(di);
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1313eeb..3039d69 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2368,43 +2368,12 @@
         final Region region = inputWindowHandle.touchableRegion;
         setTouchableRegionCropIfNeeded(inputWindowHandle);
 
-        if (modal && mActivityRecord != null) {
-            // Limit the outer touch to the activity stack region.
+        if (modal) {
             flags |= FLAG_NOT_TOUCH_MODAL;
-            // If the inner bounds of letterbox is available, then it will be used as the touchable
-            // region so it won't cover the touchable letterbox and the touch events can slip to
-            // activity from letterbox.
-            mActivityRecord.getLetterboxInnerBounds(mTmpRect);
-            if (mTmpRect.isEmpty()) {
-                // If this is a modal window we need to dismiss it if it's not full screen and the
-                // touch happens outside of the frame that displays the content. This means we need
-                // to intercept touches outside of that window. The dim layer user associated with
-                // the window (task or stack) will give us the good bounds, as they would be used to
-                // display the dim layer.
-                final Task task = getTask();
-                if (task != null) {
-                    task.getDimBounds(mTmpRect);
-                } else {
-                    getStack().getDimBounds(mTmpRect);
-                }
-            }
-            if (inFreeformWindowingMode()) {
-                // For freeform windows we the touch region to include the whole surface for the
-                // shadows.
-                final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
-                final int delta = WindowManagerService.dipToPixel(
-                        RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
-                mTmpRect.inset(-delta, -delta);
-            }
-            region.set(mTmpRect);
-            cropRegionToStackBoundsIfNeeded(region);
-            subtractTouchExcludeRegionIfNeeded(region);
-        } else if (modal && mTapExcludeRegionHolder != null) {
-            final Region touchExcludeRegion = Region.obtain();
-            amendTapExcludeRegion(touchExcludeRegion);
-            if (!touchExcludeRegion.isEmpty()) {
-                // Remove touch modal because there are some areas that cannot be touched.
-                flags |= FLAG_NOT_TOUCH_MODAL;
+            if (mActivityRecord != null) {
+                // Limit the outer touch to the activity stack region.
+                updateRegionForModalActivityWindow(region);
+            } else {
                 // Give it a large touchable region at first because it was touch modal. The window
                 // might be moved on the display, so the touchable region should be large enough to
                 // ensure it covers the whole display, no matter where it is moved.
@@ -2412,15 +2381,13 @@
                 final int dw = mTmpRect.width();
                 final int dh = mTmpRect.height();
                 region.set(-dw, -dh, dw + dw, dh + dh);
-                // Subtract the area that cannot be touched.
-                region.op(touchExcludeRegion, Region.Op.DIFFERENCE);
-                inputWindowHandle.setTouchableRegionCrop(null);
             }
-            touchExcludeRegion.recycle();
+            subtractTouchExcludeRegionIfNeeded(region);
         } else {
-            // Not modal or full screen modal
+            // Not modal
             getTouchableRegion(region);
         }
+
         // Translate to surface based coordinates.
         region.translate(-mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
 
@@ -2436,6 +2403,41 @@
         return flags;
     }
 
+    /**
+     * Updates the region for a window in an Activity that was a touch modal. This will limit
+     * the outer touch to the activity stack region.
+     * @param outRegion The region to update.
+     */
+    private void updateRegionForModalActivityWindow(Region outRegion) {
+        // If the inner bounds of letterbox is available, then it will be used as the
+        // touchable region so it won't cover the touchable letterbox and the touch
+        // events can slip to activity from letterbox.
+        mActivityRecord.getLetterboxInnerBounds(mTmpRect);
+        if (mTmpRect.isEmpty()) {
+            // If this is a modal window we need to dismiss it if it's not full screen
+            // and the touch happens outside of the frame that displays the content. This
+            // means we need to intercept touches outside of that window. The dim layer
+            // user associated with the window (task or stack) will give us the good
+            // bounds, as they would be used to display the dim layer.
+            final Task task = getTask();
+            if (task != null) {
+                task.getDimBounds(mTmpRect);
+            } else {
+                getStack().getDimBounds(mTmpRect);
+            }
+        }
+        if (inFreeformWindowingMode()) {
+            // For freeform windows, we need the touch region to include the whole
+            // surface for the shadows.
+            final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
+            final int delta = WindowManagerService.dipToPixel(
+                    RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
+            mTmpRect.inset(-delta, -delta);
+        }
+        outRegion.set(mTmpRect);
+        cropRegionToStackBoundsIfNeeded(outRegion);
+    }
+
     void checkPolicyVisibilityChange() {
         if (isLegacyPolicyVisibility() != mLegacyPolicyVisibilityAfterAnim) {
             if (DEBUG_VISIBILITY) {
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index c43328f..afce260 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -351,10 +351,13 @@
     {
         metadata::Mount m;
         m.mutable_storage()->set_id(ifs->mountId);
+        m.mutable_loader()->set_type((int)dataLoaderParams.type);
         m.mutable_loader()->set_package_name(dataLoaderParams.packageName);
-        m.mutable_loader()->set_arguments(dataLoaderParams.staticArgs);
+        m.mutable_loader()->set_class_name(dataLoaderParams.className);
+        m.mutable_loader()->set_arguments(dataLoaderParams.arguments);
         const auto metadata = m.SerializeAsString();
         m.mutable_loader()->release_arguments();
+        m.mutable_loader()->release_class_name();
         m.mutable_loader()->release_package_name();
         if (auto err = mIncFs->makeFile(ifs->control, constants().infoMdName, INCFS_ROOT_INODE, 0,
                                         metadata);
@@ -794,7 +797,7 @@
     }
     bool started = false;
     std::unique_lock l(ifs->lock);
-    if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_READY) {
+    if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
         if (ifs->dataLoaderReady.wait_for(l, Seconds(5)) == std::cv_status::timeout) {
             LOG(ERROR) << "Timeout waiting for data loader to be ready";
             return false;
@@ -917,8 +920,10 @@
     }
 
     DataLoaderParamsParcel dlParams;
+    dlParams.type = (DataLoaderType)m.loader().type();
     dlParams.packageName = std::move(*m.mutable_loader()->mutable_package_name());
-    dlParams.staticArgs = std::move(*m.mutable_loader()->mutable_arguments());
+    dlParams.className = std::move(*m.mutable_loader()->mutable_class_name());
+    dlParams.arguments = std::move(*m.mutable_loader()->mutable_arguments());
     if (!prepareDataLoader(*ifs, &dlParams)) {
         deleteStorage(*ifs);
         return false;
@@ -955,7 +960,7 @@
     }
 
     std::unique_lock l(ifs.lock);
-    if (ifs.dataLoaderStatus == IDataLoaderStatusListener::DATA_LOADER_READY) {
+    if (ifs.dataLoaderStatus == IDataLoaderStatusListener::DATA_LOADER_CREATED) {
         LOG(INFO) << "Skipped data loader preparation because it already exists";
         return true;
     }
@@ -1008,20 +1013,20 @@
             }
             break;
         }
-        case IDataLoaderStatusListener::DATA_LOADER_READY: {
+        case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
+            ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STARTED;
+            break;
+        }
+        case IDataLoaderStatusListener::DATA_LOADER_CREATED: {
             ifs->dataLoaderReady.notify_one();
             break;
         }
-        case IDataLoaderStatusListener::DATA_LOADER_NOT_READY: {
+        case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
             ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED;
             incrementalService.deleteStorageLocked(*ifs, std::move(l));
             break;
         }
-        case IDataLoaderStatusListener::DATA_LOADER_RUNNING: {
-            break;
-        }
-        case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
-            ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_RUNNING;
+        case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
             break;
         }
         case IDataLoaderStatusListener::DATA_LOADER_STOPPED: {
diff --git a/services/incremental/Metadata.proto b/services/incremental/Metadata.proto
index 0ff3c32..79f1bf8 100644
--- a/services/incremental/Metadata.proto
+++ b/services/incremental/Metadata.proto
@@ -10,7 +10,9 @@
 
 message DataLoader {
     string package_name = 1;
+    string class_name = 3;
     string arguments = 2;
+    int32 type = 4;
 }
 
 message Storage {
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index f6b123d..ca1e1a9 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -138,10 +138,10 @@
                 .WillByDefault(Invoke(this, &MockIncrementalManager::startDataLoaderOk));
     }
     void setDataLoaderStatusNotReady() {
-        mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_NOT_READY);
+        mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
     }
     void setDataLoaderStatusReady() {
-        mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_READY);
+        mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED);
     }
 
 private:
@@ -235,7 +235,7 @@
         MockServiceManager serviceManager = MockServiceManager(mVold, mIncrementalManager, mIncFs);
         mIncrementalService = std::make_unique<IncrementalService>(serviceManager, mRootDir.path);
         mDataLoaderParcel.packageName = "com.test";
-        mDataLoaderParcel.staticArgs = "uri";
+        mDataLoaderParcel.arguments = "uri";
         mIncrementalService->onSystemReady();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 37ff06a..c080332 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -16,12 +16,6 @@
 
 package com.android.server.integrity;
 
-import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
-
-import static org.mockito.Mockito.verify;
-
-import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 
 import androidx.test.InstrumentationRegistry;
@@ -56,17 +50,7 @@
     }
 
     @Test
-    public void integrityVerification_allow() {
-        int verificationId = 2;
-        Intent integrityVerificationIntent = new Intent();
-        integrityVerificationIntent.setAction(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
-        integrityVerificationIntent.putExtra(EXTRA_VERIFICATION_ID, verificationId);
-
-        // We cannot send the broadcast using the context since it is a protected broadcast and
-        // we will get a security exception.
-        mService.handleIntegrityVerification(integrityVerificationIntent);
-
-        verify(mPackageManagerInternal)
-                .setIntegrityVerificationResult(verificationId, PackageManager.VERIFICATION_ALLOW);
+    public void noop() {
+        // We need this test just as a place holder since an empty test suite is treated as error.
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
index ad74901..0bb2d44 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
@@ -44,48 +44,66 @@
 @RunWith(JUnit4.class)
 public class RuleXmlSerializerTest {
 
+    private static final String SAMPLE_INSTALLER_NAME = "com.test.installer";
+    private static final String SAMPLE_INSTALLER_CERT = "installer_cert";
+
     @Test
-    public void testXmlString_serializeEmptyRule() throws Exception {
-        Rule rule = null;
+    public void testXmlString_serializeEmptyRuleList() throws Exception {
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         String expectedRules = "<RL />";
 
         byte[] actualRules =
                 xmlSerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
+                        Collections.emptyList(), /* formatVersion= */ Optional.empty());
 
         assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
-    public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception {
-        Rule rule1 = null;
-        Rule rule2 =
+    public void testXmlString_serializeMultipleRules_indexingOrderPreserved() throws Exception {
+        String packageNameA = "aaa";
+        String packageNameB = "bbb";
+        String packageNameC = "ccc";
+        String appCert1 = "cert1";
+        String appCert2 = "cert2";
+        String appCert3 = "cert3";
+        Rule installerRule =
                 new Rule(
-                        new AtomicFormula.StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                "com.app.test",
-                                /* isHashedValue= */ false),
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.INSTALLER_NAME,
+                                                SAMPLE_INSTALLER_NAME,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.INSTALLER_CERTIFICATE,
+                                                SAMPLE_INSTALLER_CERT,
+                                                /* isHashedValue= */ false))),
                         Rule.DENY);
-        RuleSerializer xmlSerializer = new RuleXmlSerializer();
-        Map<String, String> packageNameAttrs = new LinkedHashMap<>();
-        packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
-        packageNameAttrs.put("V", "com.app.test");
-        packageNameAttrs.put("H", "false");
-        String expectedRules =
-                "<RL>"
-                        + generateTagWithAttribute(
-                                /* tag= */ "R",
-                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                                /* closed= */ false)
-                        + generateTagWithAttribute(
-                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                        + "</R>"
-                        + "</RL>";
 
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
         byte[] actualRules =
                 xmlSerializer.serialize(
-                        Arrays.asList(rule1, rule2), /* formatVersion= */ Optional.empty());
+                        Arrays.asList(
+                                installerRule,
+                                getRuleWithAppCertificateAndSampleInstallerName(appCert1),
+                                getRuleWithPackageNameAndSampleInstallerName(packageNameB),
+                                getRuleWithAppCertificateAndSampleInstallerName(appCert3),
+                                getRuleWithPackageNameAndSampleInstallerName(packageNameC),
+                                getRuleWithAppCertificateAndSampleInstallerName(appCert2),
+                                getRuleWithPackageNameAndSampleInstallerName(packageNameA)),
+                        /* formatVersion= */ Optional.empty());
+
+        String expectedRules = "<RL>"
+                + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameA)
+                + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameB)
+                + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameC)
+                + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert1)
+                + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert2)
+                + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert3)
+                + getSerializedCompoundRuleWithSampleInstallerNameAndCert()
+                + "</RL>";
 
         assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
@@ -371,7 +389,7 @@
 
         assertExpectException(
                 RuleSerializeException.class,
-                /* expectedExceptionMessageRegex */ "Invalid formula type",
+                /* expectedExceptionMessageRegex */ "Malformed rule identified.",
                 () ->
                         xmlSerializer.serialize(
                                 Collections.singletonList(rule),
@@ -393,6 +411,124 @@
         return res.toString();
     }
 
+    private Rule getRuleWithPackageNameAndSampleInstallerName(String packageName) {
+        return new Rule(
+                new CompoundFormula(
+                        CompoundFormula.AND,
+                        Arrays.asList(
+                                new AtomicFormula.StringAtomicFormula(
+                                        AtomicFormula.PACKAGE_NAME,
+                                        packageName,
+                                        /* isHashedValue= */ false),
+                                new AtomicFormula.StringAtomicFormula(
+                                        AtomicFormula.INSTALLER_NAME,
+                                        SAMPLE_INSTALLER_NAME,
+                                        /* isHashedValue= */ false))),
+                Rule.DENY);
+    }
+
+    private String getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(
+            String packageName) {
+
+        Map<String, String> packageNameAttrs = new LinkedHashMap<>();
+        packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
+        packageNameAttrs.put("V", packageName);
+        packageNameAttrs.put("H", "false");
+
+        Map<String, String> installerNameAttrs = new LinkedHashMap<>();
+        installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME));
+        installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME);
+        installerNameAttrs.put("H", "false");
+
+        return generateTagWithAttribute(
+                        /* tag= */ "R",
+                        Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                        /* closed= */ false)
+                + generateTagWithAttribute(
+                        /* tag= */ "OF",
+                        Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
+                        /* closed= */ false)
+                + generateTagWithAttribute(
+                        /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                + generateTagWithAttribute(
+                        /* tag= */ "AF", installerNameAttrs, /* closed= */ true)
+                + "</OF>"
+                + "</R>";
+    }
+
+
+    private Rule getRuleWithAppCertificateAndSampleInstallerName(String certificate) {
+        return new Rule(
+                new CompoundFormula(
+                        CompoundFormula.AND,
+                        Arrays.asList(
+                                new AtomicFormula.StringAtomicFormula(
+                                        AtomicFormula.APP_CERTIFICATE,
+                                        certificate,
+                                        /* isHashedValue= */ false),
+                                new AtomicFormula.StringAtomicFormula(
+                                        AtomicFormula.INSTALLER_NAME,
+                                        SAMPLE_INSTALLER_NAME,
+                                        /* isHashedValue= */ false))),
+                Rule.DENY);
+    }
+
+    private String getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(
+            String appCert) {
+
+        Map<String, String> packageNameAttrs = new LinkedHashMap<>();
+        packageNameAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
+        packageNameAttrs.put("V", appCert);
+        packageNameAttrs.put("H", "false");
+
+        Map<String, String> installerNameAttrs = new LinkedHashMap<>();
+        installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME));
+        installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME);
+        installerNameAttrs.put("H", "false");
+
+        return generateTagWithAttribute(
+                        /* tag= */ "R",
+                        Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                        /* closed= */ false)
+                + generateTagWithAttribute(
+                        /* tag= */ "OF",
+                        Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
+                        /* closed= */ false)
+                + generateTagWithAttribute(
+                        /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                + generateTagWithAttribute(
+                        /* tag= */ "AF", installerNameAttrs, /* closed= */ true)
+                + "</OF>"
+                + "</R>";
+    }
+
+    private String getSerializedCompoundRuleWithSampleInstallerNameAndCert() {
+        Map<String, String> installerNameAttrs = new LinkedHashMap<>();
+        installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME));
+        installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME);
+        installerNameAttrs.put("H", "false");
+
+        Map<String, String> installerCertAttrs = new LinkedHashMap<>();
+        installerCertAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_CERTIFICATE));
+        installerCertAttrs.put("V", SAMPLE_INSTALLER_CERT);
+        installerCertAttrs.put("H", "false");
+
+        return generateTagWithAttribute(
+                        /* tag= */ "R",
+                        Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                        /* closed= */ false)
+                + generateTagWithAttribute(
+                        /* tag= */ "OF",
+                        Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
+                        /* closed= */ false)
+                + generateTagWithAttribute(
+                        /* tag= */ "AF", installerNameAttrs, /* closed= */ true)
+                + generateTagWithAttribute(
+                        /* tag= */ "AF", installerCertAttrs, /* closed= */ true)
+                + "</OF>"
+                + "</R>";
+    }
+
     private Formula getInvalidFormula() {
         return new Formula() {
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
index ebd3633..1fff4f0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
@@ -17,8 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageManager;
-import com.android.server.pm.PackageVerificationState;
-
+import android.content.pm.PackageManagerInternal;
 import android.test.AndroidTestCase;
 
 public class PackageVerificationStateTest extends AndroidTestCase {
@@ -29,7 +28,8 @@
     private static final int SUFFICIENT_UID_2 = 8938;
 
     public void testPackageVerificationState_OnlyRequiredVerifier_AllowedInstall() {
-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
 
         assertFalse("Verification should not be marked as complete yet",
                 state.isVerificationComplete());
@@ -44,7 +44,8 @@
     }
 
     public void testPackageVerificationState_OnlyRequiredVerifier_DeniedInstall() {
-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
 
         assertFalse("Verification should not be marked as complete yet",
                 state.isVerificationComplete());
@@ -59,7 +60,8 @@
     }
 
     public void testPackageVerificationState_RequiredAndOneSufficient_RequiredDeniedInstall() {
-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
 
         assertFalse("Verification should not be marked as complete yet",
                 state.isVerificationComplete());
@@ -84,7 +86,8 @@
     }
 
     public void testPackageVerificationState_RequiredAndOneSufficient_SufficientDeniedInstall() {
-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
 
         assertFalse("Verification should not be marked as complete yet",
                 state.isVerificationComplete());
@@ -109,7 +112,8 @@
     }
 
     public void testPackageVerificationState_RequiredAndTwoSufficient_OneSufficientIsEnough() {
-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
 
         assertFalse("Verification should not be marked as complete yet",
                 state.isVerificationComplete());
@@ -135,7 +139,8 @@
     }
 
     public void testPackageVerificationState_RequiredAndTwoSufficient_SecondSufficientIsEnough() {
-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
 
         assertFalse("Verification should not be marked as complete yet",
                 state.isVerificationComplete());
@@ -166,7 +171,8 @@
     }
 
     public void testPackageVerificationState_RequiredAndTwoSufficient_RequiredOverrides() {
-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
 
         assertFalse("Verification should not be marked as complete yet",
                 state.isVerificationComplete());
@@ -202,4 +208,55 @@
         assertTrue("Installation should be marked as allowed still",
                 state.isInstallAllowed());
     }
+
+    public void testAreAllVerificationsComplete_onlyVerificationPasses() {
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
+        assertFalse(state.areAllVerificationsComplete());
+
+        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_ALLOW);
+
+        assertFalse(state.areAllVerificationsComplete());
+    }
+
+    public void testAreAllVerificationsComplete_onlyIntegrityCheckPasses() {
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
+        assertFalse(state.areAllVerificationsComplete());
+
+        state.setIntegrityVerificationResult(PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+
+        assertFalse(state.areAllVerificationsComplete());
+    }
+
+    public void testAreAllVerificationsComplete_bothPasses() {
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
+        assertFalse(state.areAllVerificationsComplete());
+
+        state.setIntegrityVerificationResult(PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_ALLOW);
+
+        assertTrue(state.areAllVerificationsComplete());
+    }
+
+    public void testAreAllVerificationsComplete_onlyVerificationFails() {
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
+        assertFalse(state.areAllVerificationsComplete());
+
+        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_REJECT);
+
+        assertFalse(state.areAllVerificationsComplete());
+    }
+
+    public void testAreAllVerificationsComplete_onlyIntegrityCheckFails() {
+        PackageVerificationState state = new PackageVerificationState(null);
+        state.setRequiredVerifierUid(REQUIRED_UID);
+        assertFalse(state.areAllVerificationsComplete());
+
+        state.setIntegrityVerificationResult(PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
+
+        assertFalse(state.areAllVerificationsComplete());
+    }
 }
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 89723d1..65704c8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -19,6 +19,7 @@
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.os.Process.NOBODY_UID;
@@ -62,6 +63,7 @@
 import static org.mockito.Mockito.never;
 
 import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
@@ -70,6 +72,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
@@ -376,6 +379,64 @@
     }
 
     @Test
+    public void ignoreRequestedOrientationInFreeformWindows() {
+        mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+        final Rect stableRect = new Rect();
+        mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
+        final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
+        final Rect bounds = new Rect(stableRect);
+        if (isScreenPortrait) {
+            // Landscape bounds
+            final int newHeight = stableRect.width() - 10;
+            bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
+            bounds.bottom = bounds.top + newHeight;
+        } else {
+            // Portrait bounds
+            final int newWidth = stableRect.height() - 10;
+            bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
+            bounds.right = bounds.left + newWidth;
+        }
+        mTask.setBounds(bounds);
+
+        // Requests orientation that's different from its bounds.
+        mActivity.setRequestedOrientation(
+                isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
+
+        // Asserts it has orientation derived from bounds.
+        assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
+                mActivity.getConfiguration().orientation);
+    }
+
+    @Test
+    public void ignoreRequestedOrientationInSplitWindows() {
+        mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        final Rect stableRect = new Rect();
+        mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
+        final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
+        final Rect bounds = new Rect(stableRect);
+        if (isScreenPortrait) {
+            // Landscape bounds
+            final int newHeight = stableRect.width() - 10;
+            bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
+            bounds.bottom = bounds.top + newHeight;
+        } else {
+            // Portrait bounds
+            final int newWidth = stableRect.height() - 10;
+            bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
+            bounds.right = bounds.left + newWidth;
+        }
+        mTask.setBounds(bounds);
+
+        // Requests orientation that's different from its bounds.
+        mActivity.setRequestedOrientation(
+                isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
+
+        // Asserts it has orientation derived from bounds.
+        assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
+                mActivity.getConfiguration().orientation);
+    }
+
+    @Test
     public void testShouldMakeActive_deferredResume() {
         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
 
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 1a18df5..de6d752 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -427,6 +427,61 @@
         assertNotEquals(origScreenH, task.getConfiguration().screenHeightDp);
     }
 
+    @Test
+    public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
+        DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
+        ActivityStack stack = display.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+                true /* onTop */);
+        DisplayInfo displayInfo = new DisplayInfo();
+        mService.mContext.getDisplay().getDisplayInfo(displayInfo);
+        final int displayHeight = displayInfo.logicalHeight;
+        final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        final Configuration inOutConfig = new Configuration();
+        final Configuration parentConfig = new Configuration();
+        final int longSide = 1200;
+        final int shortSide = 600;
+        parentConfig.densityDpi = 400;
+        parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
+        parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
+        parentConfig.windowConfiguration.setRotation(ROTATION_0);
+
+        final float density = 2.5f; // densityDpi / DENSITY_DEFAULT_SCALE = 400 / 160.0f
+        final int longSideDp = 480; // longSide / density = 1200 / 400 * 160
+        final int shortSideDp = 240; // shortSide / density = 600 / 400 * 160
+        final int screenLayout = parentConfig.screenLayout
+                & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
+        final int reducedScreenLayout =
+                Configuration.reduceScreenLayout(screenLayout, longSideDp, shortSideDp);
+
+        // Portrait bounds overlapping with navigation bar, without insets.
+        inOutConfig.windowConfiguration.getBounds().set(0,
+                displayHeight - 10 - longSide,
+                shortSide,
+                displayHeight - 10);
+        // Set to freeform mode to verify bug fix.
+        inOutConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+        task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+        assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
+        assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
+        assertEquals(reducedScreenLayout, inOutConfig.screenLayout);
+
+        inOutConfig.setToDefaults();
+        // Landscape bounds overlapping with navigtion bar, without insets.
+        inOutConfig.windowConfiguration.getBounds().set(0,
+                displayHeight - 10 - shortSide,
+                longSide,
+                displayHeight - 10);
+        inOutConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+        task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+        assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
+        assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
+        assertEquals(reducedScreenLayout, inOutConfig.screenLayout);
+    }
+
     /** Ensures that the alias intent won't have target component resolved. */
     @Test
     public void testTaskIntentActivityAlias() {
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 3940a3b..9b9997f 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -485,6 +485,86 @@
             PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING})
     public @interface PreciseCallStates {}
 
+    @IntDef(value = {
+            DisconnectCause.NOT_VALID,
+            DisconnectCause.NOT_DISCONNECTED,
+            DisconnectCause.INCOMING_MISSED,
+            DisconnectCause.NORMAL,
+            DisconnectCause.LOCAL,
+            DisconnectCause.BUSY,
+            DisconnectCause.CONGESTION,
+            DisconnectCause.MMI,
+            DisconnectCause.INVALID_NUMBER,
+            DisconnectCause.NUMBER_UNREACHABLE,
+            DisconnectCause.SERVER_UNREACHABLE,
+            DisconnectCause.INVALID_CREDENTIALS,
+            DisconnectCause.OUT_OF_NETWORK,
+            DisconnectCause.SERVER_ERROR,
+            DisconnectCause.TIMED_OUT,
+            DisconnectCause.LOST_SIGNAL,
+            DisconnectCause.LIMIT_EXCEEDED,
+            DisconnectCause.INCOMING_REJECTED,
+            DisconnectCause.POWER_OFF,
+            DisconnectCause.OUT_OF_SERVICE,
+            DisconnectCause.ICC_ERROR,
+            DisconnectCause.CALL_BARRED,
+            DisconnectCause.FDN_BLOCKED,
+            DisconnectCause.CS_RESTRICTED,
+            DisconnectCause.CS_RESTRICTED_NORMAL,
+            DisconnectCause.CS_RESTRICTED_EMERGENCY,
+            DisconnectCause.UNOBTAINABLE_NUMBER,
+            DisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE,
+            DisconnectCause.CDMA_DROP,
+            DisconnectCause.CDMA_INTERCEPT,
+            DisconnectCause.CDMA_REORDER,
+            DisconnectCause.CDMA_SO_REJECT,
+            DisconnectCause.CDMA_RETRY_ORDER,
+            DisconnectCause.CDMA_ACCESS_FAILURE,
+            DisconnectCause.CDMA_PREEMPTED,
+            DisconnectCause.CDMA_NOT_EMERGENCY,
+            DisconnectCause.CDMA_ACCESS_BLOCKED,
+            DisconnectCause.ERROR_UNSPECIFIED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DisconnectCauses {
+    }
+
+    @IntDef(value = {
+            PreciseDisconnectCause.NOT_VALID,
+            PreciseDisconnectCause.NO_DISCONNECT_CAUSE_AVAILABLE,
+            PreciseDisconnectCause.UNOBTAINABLE_NUMBER,
+            PreciseDisconnectCause.NORMAL,
+            PreciseDisconnectCause.BUSY,
+            PreciseDisconnectCause.NUMBER_CHANGED,
+            PreciseDisconnectCause.STATUS_ENQUIRY,
+            PreciseDisconnectCause.NORMAL_UNSPECIFIED,
+            PreciseDisconnectCause.NO_CIRCUIT_AVAIL,
+            PreciseDisconnectCause.TEMPORARY_FAILURE,
+            PreciseDisconnectCause.SWITCHING_CONGESTION,
+            PreciseDisconnectCause.CHANNEL_NOT_AVAIL,
+            PreciseDisconnectCause.QOS_NOT_AVAIL,
+            PreciseDisconnectCause.BEARER_NOT_AVAIL,
+            PreciseDisconnectCause.ACM_LIMIT_EXCEEDED,
+            PreciseDisconnectCause.CALL_BARRED,
+            PreciseDisconnectCause.FDN_BLOCKED,
+            PreciseDisconnectCause.IMSI_UNKNOWN_IN_VLR,
+            PreciseDisconnectCause.IMEI_NOT_ACCEPTED,
+            PreciseDisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE,
+            PreciseDisconnectCause.CDMA_DROP,
+            PreciseDisconnectCause.CDMA_INTERCEPT,
+            PreciseDisconnectCause.CDMA_REORDER,
+            PreciseDisconnectCause.CDMA_SO_REJECT,
+            PreciseDisconnectCause.CDMA_RETRY_ORDER,
+            PreciseDisconnectCause.CDMA_ACCESS_FAILURE,
+            PreciseDisconnectCause.CDMA_PREEMPTED,
+            PreciseDisconnectCause.CDMA_NOT_EMERGENCY,
+            PreciseDisconnectCause.CDMA_ACCESS_BLOCKED,
+            PreciseDisconnectCause.ERROR_UNSPECIFIED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PreciseDisconnectCauses {
+    }
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"RIL_RADIO_TECHNOLOGY_" }, value = {
             ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN,
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index b7dab16..e523fba 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -19,6 +19,7 @@
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -181,7 +182,8 @@
      * @return a CellLocation object for this CellIdentity
      * @hide
      */
-    public abstract CellLocation asCellLocation();
+    @SystemApi
+    public abstract @NonNull CellLocation asCellLocation();
 
     @Override
     public boolean equals(Object other) {
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 880d3db..54236b42 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.telephony.cdma.CdmaCellLocation;
 
@@ -198,6 +199,7 @@
     }
 
     /** @hide */
+    @NonNull
     @Override
     public CdmaCellLocation asCellLocation() {
         CdmaCellLocation cl = new CdmaCellLocation();
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 25c6577..4e4454d 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
@@ -200,6 +201,7 @@
     }
 
     /** @hide */
+    @NonNull
     @Override
     public GsmCellLocation asCellLocation() {
         GsmCellLocation cl = new GsmCellLocation();
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 997b19f..c3fc73b 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -232,6 +233,7 @@
      *
      * @hide
      */
+    @NonNull
     @Override
     public GsmCellLocation asCellLocation() {
         GsmCellLocation cl = new GsmCellLocation();
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index edc838c..e3fec7b 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -17,6 +17,7 @@
 package android.telephony;
 
 import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -77,6 +78,7 @@
      * @return a CellLocation object for this CellIdentity.
      * @hide
      */
+    @NonNull
     @Override
     public CellLocation asCellLocation() {
         return new GsmCellLocation();
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 558e346..8f812b6 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -171,6 +171,7 @@
     }
 
     /** @hide */
+    @NonNull
     @Override
     public GsmCellLocation asCellLocation() {
         GsmCellLocation cl = new GsmCellLocation();
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 031fed1..556bc32 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
@@ -196,6 +197,7 @@
     }
 
     /** @hide */
+    @NonNull
     @Override
     public GsmCellLocation asCellLocation() {
         GsmCellLocation cl = new GsmCellLocation();
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index 9f75332..bfa6326 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -16,19 +16,18 @@
 
 package android.telephony;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.DisconnectCauses;
 import android.telephony.Annotation.PreciseCallStates;
+import android.telephony.Annotation.PreciseDisconnectCauses;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseDisconnectCause;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -73,19 +72,26 @@
     private @PreciseCallStates int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
     private @PreciseCallStates int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
     private @PreciseCallStates int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
-    private int mDisconnectCause = DisconnectCause.NOT_VALID;
-    private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
+    private @DisconnectCauses int mDisconnectCause = DisconnectCause.NOT_VALID;
+    private @PreciseDisconnectCauses int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
 
     /**
-     * Constructor
+     * Construct PreciseCallState with parameters
+     *
+     * @param ringingCall ring call state
+     * @param foregroundCall foreground call state
+     * @param backgroundCall background call state
+     * @param disconnectCause disconnect cause
+     * @param preciseDisconnectCause precise disconnect cause
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public PreciseCallState(@PreciseCallStates int ringingCall,
                             @PreciseCallStates int foregroundCall,
-                            @PreciseCallStates int backgroundCall, int disconnectCause,
-                            int preciseDisconnectCause) {
+                            @PreciseCallStates int backgroundCall,
+                            @DisconnectCauses int disconnectCause,
+                            @PreciseDisconnectCauses int preciseDisconnectCause) {
         mRingingCallState = ringingCall;
         mForegroundCallState = foregroundCall;
         mBackgroundCallState = backgroundCall;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 60fda09..a96325e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1950,14 +1950,9 @@
                 return null;
             }
 
-            Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName(),
+            CellIdentity cellIdentity = telephony.getCellLocation(mContext.getOpPackageName(),
                     mContext.getFeatureId());
-            if (bundle == null || bundle.isEmpty()) {
-                Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable");
-                return null;
-            }
-
-            CellLocation cl = CellLocation.newFromBundle(bundle);
+            CellLocation cl = cellIdentity.asCellLocation();
             if (cl == null || cl.isEmpty()) {
                 Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or"
                         + " phone type doesn't match CellLocation type");
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 97b24ae..0baac71 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -30,6 +30,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.CarrierRestrictionRules;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.ClientRequestStats;
 import android.telephony.IccOpenLogicalChannelResponse;
@@ -305,7 +306,8 @@
      */
     boolean isDataConnectivityPossible(int subId);
 
-    Bundle getCellLocation(String callingPkg, String callingFeatureId);
+    // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
+    CellIdentity getCellLocation(String callingPkg, String callingFeatureId);
 
     /**
      * Returns the ISO country code equivalent of the current registered
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml
index 51bcdea..55704ed 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/ApkVerityTest/AndroidTest.xml
@@ -22,7 +22,7 @@
     <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
         <!-- Disable package verifier prevents it holding the target APK's fd that prevents cache
              eviction. -->
-        <option name="set-global-setting" key="package_verifier_enable" value="0" />
+        <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
         <option name="restore-settings" value="true" />
 
         <!-- Skip in order to prevent reboot that confuses the test flow. -->
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
index b8c82fd..4fa93ee 100644
--- a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -17,32 +17,46 @@
 package android.net.wifi;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.os.Handler;
+import android.util.SparseArray;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
 
 /**
  * Easy Connect (DPP) Status Callback. Use this callback to get status updates (success, failure,
  * progress) from the Easy Connect operation started with
- * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String,
- * int, int, Handler, EasyConnectStatusCallback)} or
- * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
- * Handler, EasyConnectStatusCallback)}
+ * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Executor,
+ * EasyConnectStatusCallback)} or {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
+ * Executor, EasyConnectStatusCallback)}
  *
  * @hide
  */
 @SystemApi
 public abstract class EasyConnectStatusCallback {
     /**
-     * Easy Connect Success event: Configuration sent (Configurator mode).
+     * Easy Connect R1 Success event: Configuration sent (Configurator mode). This is the last
+     * and final Easy Connect event when either the local device or remote device implement R1.
+     * If both devices implement R2, this event will never be received, and the
+     * {@link EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED} will be received.
      */
     public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
 
+    /**
+     * East Connect R2 Success event: Configuration applied by Enrollee (Configurator mode).
+     * This is the last and final Easy Connect event when both the local device and remote device
+     * implement R2. If either the local device or remote device implement R1, this event will never
+     * be received, and the {@link EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT} will be received.
+     */
+    public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1;
+
     /** @hide */
     @IntDef(prefix = {"EASY_CONNECT_EVENT_SUCCESS_"}, value = {
             EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
+            EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EasyConnectSuccessStatusCode {
@@ -58,10 +72,22 @@
      */
     public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1;
 
+    /**
+     * Easy Connect R2 Progress event: Configuration sent to Enrollee, waiting for response
+     */
+    public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2;
+
+    /**
+     * Easy Connect R2 Progress event: Configuration accepted by Enrollee, waiting for response
+     */
+    public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3;
+
     /** @hide */
     @IntDef(prefix = {"EASY_CONNECT_EVENT_PROGRESS_"}, value = {
             EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
             EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING,
+            EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE,
+            EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EasyConnectProgressStatusCode {
@@ -114,6 +140,20 @@
      */
     public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9;
 
+    /**
+     * Easy Connect R2 Failure event: Enrollee cannot find the network.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK = -10;
+
+    /**
+     * Easy Connect R2 Failure event: Enrollee failed to authenticate with the network.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION = -11;
+
+    /**
+     * Easy Connect R2 Failure event: Enrollee rejected the configuration.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12;
 
     /** @hide */
     @IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
@@ -126,6 +166,9 @@
             EASY_CONNECT_EVENT_FAILURE_GENERIC,
             EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
             EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
+            EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
+            EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION,
+            EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EasyConnectFailureStatusCode {
@@ -138,9 +181,8 @@
      * current Easy Connect
      * session, and no further callbacks will be called. This callback is the successful outcome
      * of a Easy Connect flow starting with
-     * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
-     * Handler,
-     * EasyConnectStatusCallback)}.
+     * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String, Executor,
+     * EasyConnectStatusCallback)} .
      *
      * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
      */
@@ -148,13 +190,11 @@
 
     /**
      * Called when a Easy Connect success event takes place, except for when configuration is
-     * received from
-     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
-     * This callback marks the successful end of the current Easy Connect session, and no further
-     * callbacks will be called. This callback is the successful outcome of a Easy Connect flow
-     * starting with
-     * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Handler,
-     * EasyConnectStatusCallback)}.
+     * received from an external Configurator. The callback onSuccessConfigReceived will be used in
+     * this case. This callback marks the successful end of the current Easy Connect session, and no
+     * further callbacks will be called. This callback is the successful outcome of a Easy Connect
+     * flow starting with {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int,
+     * int, Executor,EasyConnectStatusCallback)}.
      *
      * @param code Easy Connect success status code.
      */
@@ -162,12 +202,36 @@
 
     /**
      * Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
-     * end of the
-     * current Easy Connect session, and no further callbacks will be called.
+     * end of the current Easy Connect session, and no further callbacks will be called.
      *
      * @param code Easy Connect failure status code.
      */
-    public abstract void onFailure(@EasyConnectFailureStatusCode int code);
+    public void onFailure(@EasyConnectFailureStatusCode int code) {}
+
+    /**
+     * Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
+     * end of the current Easy Connect session, and no further callbacks will be called.
+     *
+     * Note: Easy Connect (DPP) R2, provides additional details for the Configurator when the
+     * remote Enrollee is unable to connect to a network. The ssid, channelList and bandList
+     * inputs are initialized only for the EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK failure
+     * code, and the ssid and bandList are initialized for the
+     * EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION failure code.
+     *
+     * @param code Easy Connect failure status code.
+     * @param ssid SSID of the network the Enrollee tried to connect to.
+     * @param channelListArray List of Global Operating classes and channel sets the Enrollee used
+     *                         to scan to find the network, see the "DPP Connection Status Object"
+     *                         section in the specification for the format, and Table E-4 in
+     *                         IEEE Std 802.11-2016 - Global operating classes for more details.
+     * @param operatingClassArray Array of bands the Enrollee supports as expressed as the Global
+     *                            Operating Class, see Table E-4 in IEEE Std 802.11-2016 - Global
+     *                            operating classes.
+     */
+    public void onFailure(@EasyConnectFailureStatusCode int code, @Nullable String ssid,
+            @NonNull SparseArray<int[]> channelListArray, @NonNull int[] operatingClassArray) {
+        onFailure(code);
+    }
 
     /**
      * Called when Easy Connect events that indicate progress take place. Can be used by UI elements
diff --git a/wifi/java/android/net/wifi/IDppCallback.aidl b/wifi/java/android/net/wifi/IDppCallback.aidl
index c452c76..d7a958a 100644
--- a/wifi/java/android/net/wifi/IDppCallback.aidl
+++ b/wifi/java/android/net/wifi/IDppCallback.aidl
@@ -38,7 +38,7 @@
     /**
      * Called when DPP Failure events take place.
      */
-    void onFailure(int status);
+    void onFailure(int status, String ssid, String channelList, in int[] bandArray);
 
     /**
      * Called when DPP events that indicate progress take place. Can be used by UI elements
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b98d64d..5ab0583 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -54,6 +54,7 @@
 import android.util.CloseGuard;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -70,6 +71,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.StringTokenizer;
 import java.util.concurrent.Executor;
 
 /**
@@ -5177,6 +5179,7 @@
         @Override
         public void onSuccessConfigReceived(int newNetworkId) {
             Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
+            Binder.clearCallingIdentity();
             mExecutor.execute(() -> {
                 mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
             });
@@ -5185,22 +5188,28 @@
         @Override
         public void onSuccess(int status) {
             Log.d(TAG, "Easy Connect onSuccess callback");
+            Binder.clearCallingIdentity();
             mExecutor.execute(() -> {
                 mEasyConnectStatusCallback.onConfiguratorSuccess(status);
             });
         }
 
         @Override
-        public void onFailure(int status) {
+        public void onFailure(int status, String ssid, String channelList,
+                int[] operatingClassArray) {
             Log.d(TAG, "Easy Connect onFailure callback");
+            Binder.clearCallingIdentity();
             mExecutor.execute(() -> {
-                mEasyConnectStatusCallback.onFailure(status);
+                SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
+                mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
+                        operatingClassArray);
             });
         }
 
         @Override
         public void onProgress(int status) {
             Log.d(TAG, "Easy Connect onProgress callback");
+            Binder.clearCallingIdentity();
             mExecutor.execute(() -> {
                 mEasyConnectStatusCallback.onProgress(status);
             });
@@ -5532,4 +5541,77 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Parse the list of channels the DPP enrollee reports when it fails to find an AP.
+     *
+     * @param channelList List of channels in the format defined in the DPP specification.
+     * @return A parsed sparse array, where the operating class is the key.
+     * @hide
+     */
+    @VisibleForTesting
+    public static SparseArray<int[]> parseDppChannelList(String channelList) {
+        SparseArray<int[]> channelListArray = new SparseArray<>();
+
+        if (TextUtils.isEmpty(channelList)) {
+            return channelListArray;
+        }
+        StringTokenizer str = new StringTokenizer(channelList, ",");
+        String classStr = null;
+        List<Integer> channelsInClass = new ArrayList<>();
+
+        try {
+            while (str.hasMoreElements()) {
+                String cur = str.nextToken();
+
+                /**
+                 * Example for a channel list:
+                 *
+                 * 81/1,2,3,4,5,6,7,8,9,10,11,115/36,40,44,48,118/52,56,60,64,121/100,104,108,112,
+                 * 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
+                 *
+                 * Detect operating class by the delimiter of '/' and use a string tokenizer with
+                 * ',' as a delimiter.
+                 */
+                int classDelim = cur.indexOf('/');
+                if (classDelim != -1) {
+                    if (classStr != null) {
+                        // Store the last channel array in the sparse array, where the operating
+                        // class is the key (as an integer).
+                        int[] channelsArray = new int[channelsInClass.size()];
+                        for (int i = 0; i < channelsInClass.size(); i++) {
+                            channelsArray[i] = channelsInClass.get(i);
+                        }
+                        channelListArray.append(Integer.parseInt(classStr), channelsArray);
+                        channelsInClass = new ArrayList<>();
+                    }
+
+                    // Init a new operating class and store the first channel
+                    classStr = cur.substring(0, classDelim);
+                    String channelStr = cur.substring(classDelim + 1);
+                    channelsInClass.add(Integer.parseInt(channelStr));
+                } else {
+                    if (classStr == null) {
+                        // Invalid format
+                        Log.e(TAG, "Cannot parse DPP channel list");
+                        return new SparseArray<>();
+                    }
+                    channelsInClass.add(Integer.parseInt(cur));
+                }
+            }
+
+            // Store the last array
+            if (classStr != null) {
+                int[] channelsArray = new int[channelsInClass.size()];
+                for (int i = 0; i < channelsInClass.size(); i++) {
+                    channelsArray[i] = channelsInClass.get(i);
+                }
+                channelListArray.append(Integer.parseInt(classStr), channelsArray);
+            }
+            return channelListArray;
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "Cannot parse DPP channel list");
+            return new SparseArray<>();
+        }
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
new file mode 100644
index 0000000..b101414
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.EasyConnectStatusCallbackTest}.
+ */
+@SmallTest
+public class EasyConnectStatusCallbackTest {
+    private EasyConnectStatusCallback mEasyConnectStatusCallback = new EasyConnectStatusCallback() {
+        @Override
+        public void onEnrolleeSuccess(int newNetworkId) {
+
+        }
+
+        @Override
+        public void onConfiguratorSuccess(int code) {
+
+        }
+
+        @Override
+        public void onProgress(int code) {
+
+        }
+
+        @Override
+        public void onFailure(int code) {
+            mOnFailureR1EventReceived = true;
+            mLastCode = code;
+        }
+    };
+    private boolean mOnFailureR1EventReceived;
+    private int mLastCode;
+
+    @Before
+    public void setUp() {
+        mOnFailureR1EventReceived = false;
+        mLastCode = 0;
+    }
+
+    /**
+     * Test that the legacy R1 onFailure is called by default if the R2 onFailure is not overridden
+     * by the app.
+     */
+    @Test
+    public void testR1OnFailureCalled() {
+
+        SparseArray<int[]> channelList = new SparseArray<>();
+        int[] channelArray = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+
+        channelList.append(81, channelArray);
+        mEasyConnectStatusCallback.onFailure(
+                EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
+                "SomeSSID", channelList, new int[] {81});
+
+        assertTrue(mOnFailureR1EventReceived);
+        assertEquals(mLastCode,
+                EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK);
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 4a46744..8216611 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -89,6 +89,7 @@
 import android.os.RemoteException;
 import android.os.connectivity.WifiActivityEnergyInfo;
 import android.os.test.TestLooper;
+import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 
@@ -2089,4 +2090,63 @@
                 .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WAPI));
         assertFalse(mWifiManager.isWapiSupported());
     }
+
+    /*
+     * Test that DPP channel list is parsed correctly
+     */
+    @Test
+    public void testparseDppChannelList() throws Exception {
+        String channelList = "81/1,2,3,4,5,6,7,8,9,10,11,115/36,40,44,48";
+        SparseArray<int[]> expectedResult = new SparseArray<>();
+        expectedResult.append(81, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11});
+        expectedResult.append(115, new int[]{36, 40, 44, 48});
+
+        SparseArray<int[]> result = WifiManager.parseDppChannelList(channelList);
+        assertEquals(expectedResult.size(), result.size());
+
+        int index = 0;
+        int key;
+
+        // Compare the two primitive int arrays
+        do {
+            try {
+                key = result.keyAt(index);
+            } catch (java.lang.ArrayIndexOutOfBoundsException e) {
+                break;
+            }
+            int[] expected = expectedResult.get(key);
+            int[] output = result.get(key);
+            assertEquals(expected.length, output.length);
+            for (int i = 0; i < output.length; i++) {
+                assertEquals(expected[i], output[i]);
+            }
+            index++;
+        } while (true);
+    }
+
+    /*
+     * Test that DPP channel list parser gracefully fails for invalid input
+     */
+    @Test
+    public void testparseDppChannelListWithInvalidFormats() throws Exception {
+        String channelList = "1,2,3,4,5,6,7,8,9,10,11,36,40,44,48";
+        SparseArray<int[]> result = WifiManager.parseDppChannelList(channelList);
+        assertEquals(result.size(), 0);
+
+        channelList = "ajgalskgjalskjg3-09683dh";
+        result = WifiManager.parseDppChannelList(channelList);
+        assertEquals(result.size(), 0);
+
+        channelList = "13/abc,46////";
+        result = WifiManager.parseDppChannelList(channelList);
+        assertEquals(result.size(), 0);
+
+        channelList = "11/4,5,13/";
+        result = WifiManager.parseDppChannelList(channelList);
+        assertEquals(result.size(), 0);
+
+        channelList = "/24,6";
+        result = WifiManager.parseDppChannelList(channelList);
+        assertEquals(result.size(), 0);
+    }
 }