Merge "Adding unit tests"
diff --git a/Android.bp b/Android.bp
index b3c9e2a..2534140 100644
--- a/Android.bp
+++ b/Android.bp
@@ -688,6 +688,7 @@
     srcs: [
         "core/java/android/annotation/CallbackExecutor.java",
         "core/java/android/annotation/CheckResult.java",
+        "core/java/android/annotation/CurrentTimeMillisLong.java",
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/IntRange.java",
         "core/java/android/annotation/NonNull.java",
@@ -1127,7 +1128,6 @@
     srcs: [
         ":framework-annotations",
         "core/java/android/annotation/BytesLong.java",
-        "core/java/android/annotation/CurrentTimeMillisLong.java",
         "core/java/android/annotation/CurrentTimeSecondsLong.java",
         "core/java/android/annotation/DurationMillisLong.java",
     ],
@@ -1327,7 +1327,6 @@
     libs: [
         "framework-minus-apex",
         "unsupportedappusage",
-        "ike-stubs",
     ],
     static_libs: [
         "libphonenumber-platform",
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 7b3764a..1cc1c5f 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -385,24 +385,27 @@
     }
 
     private void onStateChangedInternal(@NonNull BlobStoreSession session) {
-        synchronized (mBlobsLock) {
-            switch (session.getState()) {
-                case STATE_ABANDONED:
-                case STATE_VERIFIED_INVALID:
-                    session.getSessionFile().delete();
+        switch (session.getState()) {
+            case STATE_ABANDONED:
+            case STATE_VERIFIED_INVALID:
+                session.getSessionFile().delete();
+                synchronized (mBlobsLock) {
                     getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
                             .remove(session.getSessionId());
                     mKnownBlobIds.remove(session.getSessionId());
                     if (LOGV) {
                         Slog.v(TAG, "Session is invalid; deleted " + session);
                     }
-                    break;
-                case STATE_COMMITTED:
-                    session.verifyBlobData();
-                    break;
-                case STATE_VERIFIED_VALID:
+                }
+                break;
+            case STATE_COMMITTED:
+                session.verifyBlobData();
+                break;
+            case STATE_VERIFIED_VALID:
+                synchronized (mBlobsLock) {
                     final int userId = UserHandle.getUserId(session.getOwnerUid());
-                    final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
+                    final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(
+                            userId);
                     BlobMetadata blob = userBlobs.get(session.getBlobHandle());
                     if (blob == null) {
                         blob = new BlobMetadata(mContext,
@@ -425,11 +428,13 @@
                     if (LOGV) {
                         Slog.v(TAG, "Successfully committed session " + session);
                     }
-                    break;
-                default:
-                    Slog.wtf(TAG, "Invalid session state: "
-                            + stateToString(session.getState()));
-            }
+                }
+                break;
+            default:
+                Slog.wtf(TAG, "Invalid session state: "
+                        + stateToString(session.getState()));
+        }
+        synchronized (mBlobsLock) {
             try {
                 writeBlobSessionsLocked();
             } catch (Exception e) {
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index dc72d6d..f8b598a 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -147,7 +147,7 @@
 
     void postReportExemptedSyncStart(String packageName, int userId);
 
-    void dumpUser(IndentingPrintWriter idpw, int userId, String pkg);
+    void dumpUser(IndentingPrintWriter idpw, int userId, List<String> pkgs);
 
     void dumpState(String[] args, PrintWriter pw);
 
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 9d6e012..932c25d 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -41,6 +41,7 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -58,6 +59,7 @@
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Keeps track of recent active state changes in apps.
@@ -721,7 +723,7 @@
         }
     }
 
-    public void dump(IndentingPrintWriter idpw, int userId, String pkg) {
+    public void dump(IndentingPrintWriter idpw, int userId, List<String> pkgs) {
         idpw.println("App Standby States:");
         idpw.increaseIndent();
         ArrayMap<String, AppUsageHistory> userHistory = mIdleHistory.get(userId);
@@ -733,7 +735,7 @@
         for (int p = 0; p < P; p++) {
             final String packageName = userHistory.keyAt(p);
             final AppUsageHistory appUsageHistory = userHistory.valueAt(p);
-            if (pkg != null && !pkg.equals(packageName)) {
+            if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(packageName)) {
                 continue;
             }
             idpw.print("package=" + packageName);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index e343478..bf61eb4 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -1505,9 +1505,9 @@
     }
 
     @Override
-    public void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
+    public void dumpUser(IndentingPrintWriter idpw, int userId, List<String> pkgs) {
         synchronized (mAppIdleLock) {
-            mAppIdleHistory.dump(idpw, userId, pkg);
+            mAppIdleHistory.dump(idpw, userId, pkgs);
         }
     }
 
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index f7a8176..487c8e1 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -38,6 +38,13 @@
         },
         ndk: {
             enabled: true,
-        }
+            apex_available: [
+                // TODO(b/145923087): Remove this once statsd binary is in apex
+                "//apex_available:platform",
+
+                "com.android.os.statsd",
+                "test_com.android.os.statsd",
+            ],
+        },
     }
 }
diff --git a/api/current.txt b/api/current.txt
index 51ae4a8..702744d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9,6 +9,7 @@
     ctor public Manifest.permission();
     field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
     field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
+    field public static final String ACCESS_CALL_AUDIO = "android.permission.ACCESS_CALL_AUDIO";
     field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
     field public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
     field public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
@@ -23489,66 +23490,54 @@
   }
 
   public final class GnssAntennaInfo implements android.os.Parcelable {
-    ctor public GnssAntennaInfo(double, @NonNull android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates, @Nullable android.location.GnssAntennaInfo.PhaseCenterVariationCorrections, @Nullable android.location.GnssAntennaInfo.SignalGainCorrections);
     method public int describeContents();
-    method public double getCarrierFrequencyMHz();
-    method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates getPhaseCenterOffsetCoordinates();
-    method @Nullable public android.location.GnssAntennaInfo.PhaseCenterVariationCorrections getPhaseCenterVariationCorrections();
-    method @Nullable public android.location.GnssAntennaInfo.SignalGainCorrections getSignalGainCorrections();
+    method @FloatRange(from=0.0f) public double getCarrierFrequencyMHz();
+    method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffset getPhaseCenterOffset();
+    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getPhaseCenterVariationCorrections();
+    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getSignalGainCorrections();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo> CREATOR;
   }
 
-  public abstract static class GnssAntennaInfo.Callback {
-    ctor public GnssAntennaInfo.Callback();
+  public static class GnssAntennaInfo.Builder {
+    ctor public GnssAntennaInfo.Builder();
+    method @NonNull public android.location.GnssAntennaInfo build();
+    method @NonNull public android.location.GnssAntennaInfo.Builder setCarrierFrequencyMHz(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterOffset(@NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterVariationCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
+  }
+
+  public static interface GnssAntennaInfo.Listener {
     method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
-    method public void onStatusChanged(int);
-    field public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
-    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
-    field public static final int STATUS_READY = 1; // 0x1
   }
 
-  public static final class GnssAntennaInfo.PhaseCenterOffsetCoordinates implements android.os.Parcelable {
-    ctor public GnssAntennaInfo.PhaseCenterOffsetCoordinates(double, double, double, double, double, double);
+  public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable {
+    ctor public GnssAntennaInfo.PhaseCenterOffset(double, double, double, double, double, double);
     method public int describeContents();
-    method public double getXCoordMillimeters();
-    method public double getXCoordUncertaintyMillimeters();
-    method public double getYCoordMillimeters();
-    method public double getYCoordUncertaintyMillimeters();
-    method public double getZCoordMillimeters();
-    method public double getZCoordUncertaintyMillimeters();
+    method @FloatRange public double getXOffsetMm();
+    method @FloatRange public double getXOffsetUncertaintyMm();
+    method @FloatRange public double getYOffsetMm();
+    method @FloatRange public double getYOffsetUncertaintyMm();
+    method @FloatRange public double getZOffsetMm();
+    method @FloatRange public double getZOffsetUncertaintyMm();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffset> CREATOR;
   }
 
-  public static final class GnssAntennaInfo.PhaseCenterVariationCorrections implements android.os.Parcelable {
-    ctor public GnssAntennaInfo.PhaseCenterVariationCorrections(@NonNull double[][], @NonNull double[][]);
+  public static final class GnssAntennaInfo.SphericalCorrections implements android.os.Parcelable {
+    ctor public GnssAntennaInfo.SphericalCorrections(@NonNull double[][], @NonNull double[][]);
     method public int describeContents();
-    method public double getDeltaPhi();
-    method public double getDeltaTheta();
-    method public int getNumColumns();
-    method public int getNumRows();
-    method public double getPhaseCenterVariationCorrectionMillimetersAt(int, int);
-    method public double getPhaseCenterVariationCorrectionUncertaintyMillimetersAt(int, int);
-    method @NonNull public double[][] getRawCorrectionUncertaintiesArray();
-    method @NonNull public double[][] getRawCorrectionsArray();
+    method @NonNull public double[][] getCorrectionUncertaintiesArray();
+    method @NonNull public double[][] getCorrectionsArray();
+    method @FloatRange(from=0.0f, to=180.0f) public double getDeltaPhi();
+    method @FloatRange(from=0.0f, to=360.0f) public double getDeltaTheta();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterVariationCorrections> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SphericalCorrections> CREATOR;
   }
 
-  public static final class GnssAntennaInfo.SignalGainCorrections implements android.os.Parcelable {
-    ctor public GnssAntennaInfo.SignalGainCorrections(@NonNull double[][], @NonNull double[][]);
-    method public int describeContents();
-    method public double getDeltaPhi();
-    method public double getDeltaTheta();
-    method public int getNumColumns();
-    method public int getNumRows();
-    method @NonNull public double[][] getRawCorrectionUncertaintiesArray();
-    method @NonNull public double[][] getRawCorrectionsArray();
-    method public double getSignalGainCorrectionDbiAt(int, int);
-    method public double getSignalGainCorrectionUncertaintyDbiAt(int, int);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SignalGainCorrections> CREATOR;
+  public final class GnssCapabilities {
+    method public boolean hasGnssAntennaInfo();
   }
 
   public final class GnssClock implements android.os.Parcelable {
@@ -23859,6 +23848,7 @@
     method @NonNull public java.util.List<java.lang.String> getAllProviders();
     method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+    method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
     method @Nullable public String getGnssHardwareModelName();
     method public int getGnssYearOfHardware();
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
@@ -23868,7 +23858,7 @@
     method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
     method public boolean isLocationEnabled();
     method public boolean isProviderEnabled(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerAntennaInfoCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
@@ -23900,7 +23890,7 @@
     method public void setTestProviderEnabled(@NonNull String, boolean);
     method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
     method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
-    method public void unregisterAntennaInfoCallback(@NonNull android.location.GnssAntennaInfo.Callback);
+    method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
     method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
     method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
@@ -31744,7 +31734,7 @@
     method public android.net.wifi.hotspot2.pps.Credential getCredential();
     method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
     method public long getSubscriptionExpirationTimeMillis();
-    method @NonNull public String getUniqueId() throws java.lang.IllegalStateException;
+    method @NonNull public String getUniqueId();
     method public boolean isOsuProvisioned();
     method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
     method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
@@ -43403,11 +43393,12 @@
 
   public abstract class ControlsProviderService extends android.app.Service {
     ctor public ControlsProviderService();
-    method public abstract void loadAvailableControls(@NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>);
-    method public void loadSuggestedControls(int, @NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>);
+    method @Deprecated public void loadAvailableControls(@NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>);
     method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void performControlAction(@NonNull String, @NonNull android.service.controls.actions.ControlAction, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>);
+    method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable();
+    method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested();
     field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService";
     field @NonNull public static final String TAG = "ControlsProviderService";
   }
@@ -46813,59 +46804,6 @@
     field public static final String KEY_WIFI_OFF_DEFERRING_TIME_INT = "ims.wifi_off_deferring_time_int";
   }
 
-  public static final class CarrierConfigManager.Iwlan {
-    field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1
-    field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0
-    field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
-    field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
-    field public static final int DH_GROUP_NONE = 0; // 0x0
-    field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3
-    field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
-    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13
-    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14
-    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12
-    field public static final int EPDG_ADDRESS_PCO = 2; // 0x2
-    field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1
-    field public static final int EPDG_ADDRESS_STATIC = 0; // 0x0
-    field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
-    field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
-    field public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = "iwlan.child_sa_rekey_hard_timer_sec_int";
-    field public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = "iwlan.child_sa_rekey_soft_timer_sec_int";
-    field public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.child_session_aes_cbc_key_size_int_array";
-    field public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.child_encryption_aes_ctr_key_size_int_array";
-    field public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY = "iwlan.diffie_hellman_groups_int_array";
-    field public static final String KEY_DPD_TIMER_SEC_INT = "iwlan.dpd_timer_sec_int";
-    field public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY = "iwlan.epdg_address_priority_int_array";
-    field public static final String KEY_EPDG_AUTHENTICATION_METHOD_INT = "iwlan.epdg_authentication_method_int";
-    field public static final String KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING = "iwlan.epdg_static_address_roaming_string";
-    field public static final String KEY_EPDG_STATIC_ADDRESS_STRING = "iwlan.epdg_static_address_string";
-    field public static final String KEY_IKE_FRAGMENTATION_ENABLED_BOOL = "iwlan.ike_fragmentation_enabled_bool";
-    field public static final String KEY_IKE_REKEY_HARD_TIMER_SEC_INT = "iwlan.ike_rekey_hard_timer_in_sec";
-    field public static final String KEY_IKE_REKEY_SOFT_TIMER_SEC_INT = "iwlan.ike_rekey_soft_timer_sec_int";
-    field public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_cbc_key_size_int_array";
-    field public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_aes_ctr_key_size_int_array";
-    field public static final int KEY_LEN_AES_128 = 128; // 0x80
-    field public static final int KEY_LEN_AES_192 = 192; // 0xc0
-    field public static final int KEY_LEN_AES_256 = 256; // 0x100
-    field public static final int KEY_LEN_UNUSED = 0; // 0x0
-    field public static final String KEY_MAX_RETRIES_INT = "iwlan.max_retries_int";
-    field public static final String KEY_MCC_MNCS_STRING_ARRAY = "iwlan.mcc_mncs_string_array";
-    field public static final String KEY_NATT_ENABLED_BOOL = "iwlan.natt_enabled_bool";
-    field public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = "iwlan.natt_keep_alive_timer_sec_int";
-    field public static final String KEY_PREFIX = "iwlan.";
-    field public static final String KEY_RETRANSMIT_TIMER_SEC_INT = "iwlan.retransmit_timer_sec_int";
-    field public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_child_session_encryption_algorithms_int_array";
-    field public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_ike_session_encryption_algorithms_int_array";
-    field public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = "iwlan.supported_integrity_algorithms_int_array";
-    field public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = "iwlan.supported_prf_algorithms_int_array";
-    field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
-    field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
-  }
-
   public abstract class CellIdentity implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public CharSequence getOperatorAlphaLong();
diff --git a/api/system-current.txt b/api/system-current.txt
index 7b8f717..202a939 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -376,6 +376,7 @@
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int);
     field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
     field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
+    field public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio";
     field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
     field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
     field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
@@ -3823,7 +3824,6 @@
 
   public final class GnssCapabilities {
     method public boolean hasGeofencing();
-    method public boolean hasGnssAntennaInfo();
     method public boolean hasLowPowerMode();
     method public boolean hasMeasurementCorrections();
     method public boolean hasMeasurementCorrectionsExcessPathLength();
@@ -4163,7 +4163,6 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
     method @Nullable public String getExtraLocationControllerPackage();
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
-    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GnssCapabilities getGnssCapabilities();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isExtraLocationControllerPackageEnabled();
     method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
@@ -9769,6 +9768,7 @@
     field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
     field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
     field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
+    field public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
     field public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
     field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
     field public static final String DOZE_ALWAYS_ON = "doze_always_on";
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 9ed4798..8f02f15 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1035,10 +1035,12 @@
     public static final int OP_ACTIVATE_PLATFORM_VPN = 94;
     /** @hide */
     public static final int OP_LOADER_USAGE_STATS = 95;
+    /** @hide Access telephony call audio */
+    public static final int OP_ACCESS_CALL_AUDIO = 96;
 
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 96;
+    public static final int _NUM_OP = 97;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1329,6 +1331,9 @@
     @SystemApi
     public static final String OPSTR_MANAGE_EXTERNAL_STORAGE =
             "android:manage_external_storage";
+    /** @hide Access telephony call audio */
+    @SystemApi
+    public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio";
 
     /** @hide Communicate cross-profile within the same profile group. */
     @SystemApi
@@ -1418,6 +1423,7 @@
             OP_MANAGE_EXTERNAL_STORAGE,
             OP_INTERACT_ACROSS_PROFILES,
             OP_LOADER_USAGE_STATS,
+            OP_ACCESS_CALL_AUDIO,
     };
 
     /**
@@ -1525,6 +1531,7 @@
             OP_INTERACT_ACROSS_PROFILES,        //INTERACT_ACROSS_PROFILES
             OP_ACTIVATE_PLATFORM_VPN,           // ACTIVATE_PLATFORM_VPN
             OP_LOADER_USAGE_STATS,              // LOADER_USAGE_STATS
+            OP_ACCESS_CALL_AUDIO,               // ACCESS_CALL_AUDIO
     };
 
     /**
@@ -1627,6 +1634,7 @@
             OPSTR_INTERACT_ACROSS_PROFILES,
             OPSTR_ACTIVATE_PLATFORM_VPN,
             OPSTR_LOADER_USAGE_STATS,
+            OPSTR_ACCESS_CALL_AUDIO,
     };
 
     /**
@@ -1730,6 +1738,7 @@
             "INTERACT_ACROSS_PROFILES",
             "ACTIVATE_PLATFORM_VPN",
             "LOADER_USAGE_STATS",
+            "ACCESS_CALL_AUDIO",
     };
 
     /**
@@ -1834,6 +1843,7 @@
             android.Manifest.permission.INTERACT_ACROSS_PROFILES,
             null, // no permission for OP_ACTIVATE_PLATFORM_VPN
             android.Manifest.permission.LOADER_USAGE_STATS,
+            Manifest.permission.ACCESS_CALL_AUDIO,
     };
 
     /**
@@ -1938,6 +1948,7 @@
             null, // INTERACT_ACROSS_PROFILES
             null, // ACTIVATE_PLATFORM_VPN
             null, // LOADER_USAGE_STATS
+            null, // ACCESS_CALL_AUDIO
     };
 
     /**
@@ -2041,6 +2052,7 @@
             false, // INTERACT_ACROSS_PROFILES
             false, // ACTIVATE_PLATFORM_VPN
             false, // LOADER_USAGE_STATS
+            false, // ACCESS_CALL_AUDIO
     };
 
     /**
@@ -2143,6 +2155,7 @@
             AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES
             AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
             AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS
+            AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO
     };
 
     /**
@@ -2249,6 +2262,7 @@
             false, // INTERACT_ACROSS_PROFILES
             false, // ACTIVATE_PLATFORM_VPN
             false, // LOADER_USAGE_STATS
+            false, // ACCESS_CALL_AUDIO
     };
 
     /**
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 130e2ec..6b1afda 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -256,10 +256,10 @@
     };
 
     @DataClass.Generated(
-            time = 1580158740502L,
+            time = 1581728574427L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
-            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=95L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=96L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java
index 0287564..8eb7e72 100644
--- a/core/java/android/app/SharedElementCallback.java
+++ b/core/java/android/app/SharedElementCallback.java
@@ -19,7 +19,6 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.ColorSpace;
-import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
@@ -48,8 +47,8 @@
 public abstract class SharedElementCallback {
     private Matrix mTempMatrix;
     private static final String BUNDLE_SNAPSHOT_BITMAP = "sharedElement:snapshot:bitmap";
-    private static final String BUNDLE_SNAPSHOT_GRAPHIC_BUFFER =
-            "sharedElement:snapshot:graphicBuffer";
+    private static final String BUNDLE_SNAPSHOT_HARDWARE_BUFFER =
+            "sharedElement:snapshot:hardwareBuffer";
     private static final String BUNDLE_SNAPSHOT_COLOR_SPACE = "sharedElement:snapshot:colorSpace";
     private static final String BUNDLE_SNAPSHOT_IMAGE_SCALETYPE = "sharedElement:snapshot:imageScaleType";
     private static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "sharedElement:snapshot:imageMatrix";
@@ -186,8 +185,8 @@
                     if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
                         bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap);
                     } else {
-                        GraphicBuffer graphicBuffer = bitmap.createGraphicBufferHandle();
-                        bundle.putParcelable(BUNDLE_SNAPSHOT_GRAPHIC_BUFFER, graphicBuffer);
+                        HardwareBuffer hardwareBuffer = bitmap.getHardwareBuffer();
+                        bundle.putParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER, hardwareBuffer);
                         ColorSpace cs = bitmap.getColorSpace();
                         if (cs != null) {
                             bundle.putInt(BUNDLE_SNAPSHOT_COLOR_SPACE, cs.getId());
@@ -235,7 +234,7 @@
         View view = null;
         if (snapshot instanceof Bundle) {
             Bundle bundle = (Bundle) snapshot;
-            GraphicBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_GRAPHIC_BUFFER);
+            HardwareBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER);
             Bitmap bitmap = bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP);
             if (buffer == null && bitmap == null) {
                 return null;
@@ -246,8 +245,7 @@
                 if (colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length) {
                     colorSpace = ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]);
                 }
-                bitmap = Bitmap.wrapHardwareBuffer(HardwareBuffer.createFromGraphicBuffer(buffer),
-                                                   colorSpace);
+                bitmap = Bitmap.wrapHardwareBuffer(buffer, colorSpace);
             }
             ImageView imageView = new ImageView(context);
             view = imageView;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f1559f7..be87f5c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -186,6 +186,7 @@
 import android.telephony.TelephonyRegistryManager;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Slog;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.WindowManager;
@@ -222,6 +223,8 @@
 public final class SystemServiceRegistry {
     private static final String TAG = "SystemServiceRegistry";
 
+    private static final boolean ENABLE_SERVICE_NOT_FOUND_WTF = true;
+
     // Service registry information.
     // This information is never changed once static initialization has completed.
     private static final Map<Class<?>, String> SYSTEM_SERVICE_NAMES =
@@ -1373,8 +1376,29 @@
      * @hide
      */
     public static Object getSystemService(ContextImpl ctx, String name) {
-        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
-        return fetcher != null ? fetcher.getService(ctx) : null;
+        if (name == null) {
+            return null;
+        }
+        final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
+        if (ENABLE_SERVICE_NOT_FOUND_WTF && fetcher == null) {
+            // This should be a caller bug.
+            Slog.wtf(TAG, "Unknown manager requested: " + name);
+            return null;
+        }
+
+        final Object ret = fetcher.getService(ctx);
+        if (ENABLE_SERVICE_NOT_FOUND_WTF && ret == null) {
+            // Some services do return null in certain situations, so don't do WTF for them.
+            switch (name) {
+                case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
+                case Context.APP_PREDICTION_SERVICE:
+                case Context.INCREMENTAL_SERVICE:
+                    return null;
+            }
+            Slog.wtf(TAG, "Manager wrapper not available: " + name);
+            return null;
+        }
+        return ret;
     }
 
     /**
@@ -1382,7 +1406,15 @@
      * @hide
      */
     public static String getSystemServiceName(Class<?> serviceClass) {
-        return SYSTEM_SERVICE_NAMES.get(serviceClass);
+        if (serviceClass == null) {
+            return null;
+        }
+        final String serviceName = SYSTEM_SERVICE_NAMES.get(serviceClass);
+        if (ENABLE_SERVICE_NOT_FOUND_WTF && serviceName == null) {
+            // This should be a caller bug.
+            Slog.wtf(TAG, "Unknown manager requested: " + serviceClass.getCanonicalName());
+        }
+        return serviceName;
     }
 
     /**
@@ -1679,7 +1711,9 @@
                         try {
                             cache.wait();
                         } catch (InterruptedException e) {
-                            Log.w(TAG, "getService() interrupted");
+                            // This shouldn't normally happen, but if someone interrupts the
+                            // thread, it will.
+                            Slog.wtf(TAG, "getService() interrupted");
                             Thread.currentThread().interrupt();
                             return null;
                         }
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 4bd31f8..a2def7f 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -20,6 +20,8 @@
 import android.annotation.Nullable;
 import android.os.IVold;
 
+import java.util.Set;
+
 /**
  * Mount service local interface.
  *
@@ -98,6 +100,12 @@
     }
 
     /**
+     * Check if fuse is running in target user, if it's running then setup its obb directories.
+     * TODO: System server should store a list of active pids that obb is not mounted and use it.
+     */
+    public abstract void prepareObbDirs(int userId, Set<String> packageList, String processName);
+
+    /**
      * Add a listener to listen to reset event in StorageManagerService.
      *
      * @param listener The listener that will be notified on reset events.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4523acb..9511152 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8760,6 +8760,13 @@
                 "location_permissions_upgrade_to_q_mode";
 
         /**
+         * Whether or not the system Auto Revoke feature is disabled.
+         * @hide
+         */
+        @SystemApi
+        public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
+
+        /**
          * Map of android.theme.customization.* categories to the enabled overlay package for that
          * category, formatted as a serialized {@link org.json.JSONObject}. If there is no
          * corresponding package included for a category, then all overlay packages in that
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index de4c056..cb20db9 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -16,6 +16,7 @@
 package android.service.controls;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
@@ -34,7 +35,6 @@
 
 import com.android.internal.util.Preconditions;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Flow.Publisher;
@@ -70,25 +70,48 @@
      * Retrieve all available controls, using the stateless builder
      * {@link Control.StatelessBuilder} to build each Control, then use the
      * provided consumer to callback to the call originator.
+     *
+     * @deprecated Removing consumer-based load apis. Use publisherForAllAvailable() instead
      */
-    public abstract void loadAvailableControls(@NonNull Consumer<List<Control>> consumer);
-
-    /**
-     * (Optional) The service may be asked to provide a small number of recommended controls, in
-     * order to suggest some controls to the user for favoriting. The controls shall be built using
-     * the stateless builder {@link Control.StatelessBuilder}, followed by an invocation to the
-     * provided consumer to callback to the call originator. If the number of controls
-     * is greater than maxNumber, the list will be truncated.
-     */
-    public void loadSuggestedControls(int maxNumber, @NonNull Consumer<List<Control>> consumer) {
-        // Override to change the default behavior
+    @Deprecated
+    public void loadAvailableControls(@NonNull Consumer<List<Control>> consumer) {
+        // pending removal
         consumer.accept(Collections.emptyList());
     }
 
     /**
-     * Return a valid Publisher for the given controlIds. This publisher will be asked
-     * to provide updates for the given list of controlIds as long as the Subscription
-     * is valid.
+     * Publisher for all available controls
+     *
+     * Retrieve all available controls. Use the stateless builder {@link Control.StatelessBuilder}
+     * to build each Control. Call {@link Subscriber#onComplete} when done loading all unique
+     * controls, or {@link Subscriber#onError} for error scenarios. Duplicate Controls will
+     * replace the original.
+     */
+    @Nullable
+    public Publisher<Control> publisherForAllAvailable() {
+        // will be abstract and @nonnull when consumers are removed
+        return null;
+    }
+
+    /**
+     * (Optional) Publisher for suggested controls
+     *
+     * The service may be asked to provide a small number of recommended controls, in
+     * order to suggest some controls to the user for favoriting. The controls shall be built using
+     * the stateless builder {@link Control.StatelessBuilder}. The number of controls requested
+     * through {@link Subscription#request} will be limited. Call {@link Subscriber#onComplete}
+     * when done, or {@link Subscriber#onError} for error scenarios.
+     */
+    @Nullable
+    public Publisher<Control> publisherForSuggested() {
+        return null;
+    }
+
+    /**
+     * Return a valid Publisher for the given controlIds. This publisher will be asked to provide
+     * updates for the given list of controlIds as long as the {@link Subscription} is valid.
+     * Calls to {@link Subscriber#onComplete} will not be expected. Instead, wait for the call from
+     * {@link Subscription#cancel} to indicate that updates are no longer required.
      */
     @NonNull
     public abstract Publisher<Control> publisherFor(@NonNull List<String> controlIds);
@@ -113,13 +136,13 @@
         mToken = bundle.getBinder(CALLBACK_TOKEN);
 
         return new IControlsProvider.Stub() {
-            public void load(IControlsLoadCallback cb) {
-                mHandler.obtainMessage(RequestHandler.MSG_LOAD, cb).sendToTarget();
+            public void load(IControlsSubscriber subscriber) {
+                mHandler.obtainMessage(RequestHandler.MSG_LOAD, subscriber).sendToTarget();
             }
 
-            public void loadSuggested(int maxNumber, IControlsLoadCallback cb) {
-                LoadMessage msg = new LoadMessage(maxNumber, cb);
-                mHandler.obtainMessage(RequestHandler.MSG_LOAD_SUGGESTED, msg).sendToTarget();
+            public void loadSuggested(IControlsSubscriber subscriber) {
+                mHandler.obtainMessage(RequestHandler.MSG_LOAD_SUGGESTED, subscriber)
+                        .sendToTarget();
             }
 
             public void subscribe(List<String> controlIds,
@@ -148,73 +171,56 @@
         private static final int MSG_ACTION = 3;
         private static final int MSG_LOAD_SUGGESTED = 4;
 
-        /**
-         * This the maximum number of controls that can be loaded via
-         * {@link ControlsProviderService#loadAvailablecontrols}. Anything over this number
-         * will be truncated.
-         */
-        private static final int MAX_NUMBER_OF_CONTROLS_ALLOWED = 1000;
-
         RequestHandler(Looper looper) {
             super(looper);
         }
 
         public void handleMessage(Message msg) {
             switch(msg.what) {
-                case MSG_LOAD:
-                    final IControlsLoadCallback cb = (IControlsLoadCallback) msg.obj;
-                    ControlsProviderService.this.loadAvailableControls(consumerFor(
-                            MAX_NUMBER_OF_CONTROLS_ALLOWED, cb));
-                    break;
+                case MSG_LOAD: {
+                    final IControlsSubscriber cs = (IControlsSubscriber) msg.obj;
+                    final SubscriberProxy proxy = new SubscriberProxy(true, mToken, cs);
 
-                case MSG_LOAD_SUGGESTED:
-                    final LoadMessage lMsg = (LoadMessage) msg.obj;
-                    ControlsProviderService.this.loadSuggestedControls(lMsg.mMaxNumber,
-                            consumerFor(lMsg.mMaxNumber, lMsg.mCb));
+                    Publisher<Control> publisher =
+                            ControlsProviderService.this.publisherForAllAvailable();
+                    if (publisher == null) {
+                        ControlsProviderService.this.loadAvailableControls(consumerFor(proxy));
+                    } else {
+                        publisher.subscribe(proxy);
+                    }
                     break;
+                }
 
-                case MSG_SUBSCRIBE:
+                case MSG_LOAD_SUGGESTED: {
+                    final IControlsSubscriber cs = (IControlsSubscriber) msg.obj;
+                    final SubscriberProxy proxy = new SubscriberProxy(true, mToken, cs);
+
+                    Publisher<Control> publisher =
+                            ControlsProviderService.this.publisherForSuggested();
+                    if (publisher == null) {
+                        Log.i(TAG, "No publisher provided for suggested controls");
+                        proxy.onComplete();
+                    } else {
+                        publisher.subscribe(proxy);
+                    }
+                    break;
+                }
+
+                case MSG_SUBSCRIBE: {
                     final SubscribeMessage sMsg = (SubscribeMessage) msg.obj;
-                    final IControlsSubscriber cs = sMsg.mSubscriber;
-                    Subscriber<Control> s = new Subscriber<Control>() {
-                            public void onSubscribe(Subscription subscription) {
-                                try {
-                                    cs.onSubscribe(mToken, new SubscriptionAdapter(subscription));
-                                } catch (RemoteException ex) {
-                                    ex.rethrowAsRuntimeException();
-                                }
-                            }
-                            public void onNext(@NonNull Control statefulControl) {
-                                Preconditions.checkNotNull(statefulControl);
-                                try {
-                                    cs.onNext(mToken, statefulControl);
-                                } catch (RemoteException ex) {
-                                    ex.rethrowAsRuntimeException();
-                                }
-                            }
-                            public void onError(Throwable t) {
-                                try {
-                                    cs.onError(mToken, t.toString());
-                                } catch (RemoteException ex) {
-                                    ex.rethrowAsRuntimeException();
-                                }
-                            }
-                            public void onComplete() {
-                                try {
-                                    cs.onComplete(mToken);
-                                } catch (RemoteException ex) {
-                                    ex.rethrowAsRuntimeException();
-                                }
-                            }
-                        };
-                    ControlsProviderService.this.publisherFor(sMsg.mControlIds).subscribe(s);
-                    break;
+                    final SubscriberProxy proxy = new SubscriberProxy(false, mToken,
+                            sMsg.mSubscriber);
 
-                case MSG_ACTION:
+                    ControlsProviderService.this.publisherFor(sMsg.mControlIds).subscribe(proxy);
+                    break;
+                }
+
+                case MSG_ACTION: {
                     final ActionMessage aMsg = (ActionMessage) msg.obj;
                     ControlsProviderService.this.performControlAction(aMsg.mControlId,
                             aMsg.mAction, consumerFor(aMsg.mControlId, aMsg.mCb));
                     break;
+                }
             }
         }
 
@@ -234,39 +240,88 @@
             };
         }
 
-        private Consumer<List<Control>> consumerFor(int maxNumber, IControlsLoadCallback cb) {
-            return (@NonNull List<Control> controls) -> {
+        /**
+         * Method will be removed during migration to publisher
+         */
+        private Consumer<List<Control>> consumerFor(final Subscriber<Control> subscriber) {
+            return (@NonNull final List<Control> controls) -> {
                 Preconditions.checkNotNull(controls);
-                if (controls.size() > maxNumber) {
-                    Log.w(TAG, "Too many controls. Provided: " + controls.size() + ", Max allowed: "
-                            + maxNumber + ". Truncating the list.");
-                    controls = controls.subList(0, maxNumber);
-                }
 
-                List<Control> list = new ArrayList<>();
-                for (Control control: controls) {
-                    if (control == null) {
-                        Log.e(TAG, "onLoad: null control.");
-                    }
-                    if (isStatelessControl(control)) {
-                        list.add(control);
-                    } else {
-                        Log.w(TAG, "onLoad: control is not stateless.");
-                        list.add(new Control.StatelessBuilder(control).build());
-                    }
-                }
-                try {
-                    cb.accept(mToken, list);
-                } catch (RemoteException ex) {
-                    ex.rethrowAsRuntimeException();
-                }
+                subscriber.onSubscribe(new Subscription() {
+                        public void request(long n) {
+                            for (Control control: controls) {
+                                Control c;
+                                if (control == null) {
+                                    Log.e(TAG, "onLoad: null control.");
+                                }
+                                if (isStatelessControl(control)) {
+                                    c = control;
+                                } else {
+                                    Log.w(TAG, "onLoad: control is not stateless.");
+                                    c = new Control.StatelessBuilder(control).build();
+                                }
+
+                                subscriber.onNext(c);
+                            }
+                            subscriber.onComplete();
+                        }
+
+                        public void cancel() {}
+                    });
             };
         }
+    }
 
-        private boolean isStatelessControl(Control control) {
-            return (control.getStatus() == Control.STATUS_UNKNOWN
-                    && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE
-                    && TextUtils.isEmpty(control.getStatusText()));
+    private static boolean isStatelessControl(Control control) {
+        return (control.getStatus() == Control.STATUS_UNKNOWN
+                && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE
+                && TextUtils.isEmpty(control.getStatusText()));
+    }
+
+    private static class SubscriberProxy implements Subscriber<Control> {
+        private IBinder mToken;
+        private IControlsSubscriber mCs;
+        private boolean mEnforceStateless;
+
+        SubscriberProxy(boolean enforceStateless, IBinder token, IControlsSubscriber cs) {
+            mEnforceStateless = enforceStateless;
+            mToken = token;
+            mCs = cs;
+        }
+
+        public void onSubscribe(Subscription subscription) {
+            try {
+                mCs.onSubscribe(mToken, new SubscriptionAdapter(subscription));
+            } catch (RemoteException ex) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
+        public void onNext(@NonNull Control control) {
+            Preconditions.checkNotNull(control);
+            try {
+                if (mEnforceStateless && !isStatelessControl(control)) {
+                    Log.w(TAG, "onNext(): control is not stateless. Use the "
+                            + "Control.StatelessBuilder() to build the control.");
+                    control = new Control.StatelessBuilder(control).build();
+                }
+                mCs.onNext(mToken, control);
+            } catch (RemoteException ex) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
+        public void onError(Throwable t) {
+            try {
+                mCs.onError(mToken, t.toString());
+            } catch (RemoteException ex) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
+        public void onComplete() {
+            try {
+                mCs.onComplete(mToken);
+            } catch (RemoteException ex) {
+                ex.rethrowAsRuntimeException();
+            }
         }
     }
 
@@ -307,14 +362,4 @@
             this.mSubscriber = subscriber;
         }
     }
-
-    private static class LoadMessage {
-        final int mMaxNumber;
-        final IControlsLoadCallback mCb;
-
-        LoadMessage(int maxNumber, IControlsLoadCallback cb) {
-            this.mMaxNumber = maxNumber;
-            this.mCb = cb;
-        }
-    }
 }
diff --git a/core/java/android/service/controls/IControlsLoadCallback.aidl b/core/java/android/service/controls/IControlsLoadCallback.aidl
deleted file mode 100644
index bfc61cd..0000000
--- a/core/java/android/service/controls/IControlsLoadCallback.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2020, 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.service.controls;
-
-import android.service.controls.Control;
-
-/**
- * @hide
- */
-oneway interface IControlsLoadCallback {
-    void accept(in IBinder token, in List<Control> controls);
-}
\ No newline at end of file
diff --git a/core/java/android/service/controls/IControlsProvider.aidl b/core/java/android/service/controls/IControlsProvider.aidl
index 4375fbb..0cb06b4 100644
--- a/core/java/android/service/controls/IControlsProvider.aidl
+++ b/core/java/android/service/controls/IControlsProvider.aidl
@@ -17,7 +17,6 @@
 package android.service.controls;
 
 import android.service.controls.IControlsActionCallback;
-import android.service.controls.IControlsLoadCallback;
 import android.service.controls.IControlsSubscriber;
 import android.service.controls.actions.ControlActionWrapper;
 
@@ -25,9 +24,9 @@
  * @hide
  */
 oneway interface IControlsProvider {
-    void load(IControlsLoadCallback cb);
+    void load(IControlsSubscriber subscriber);
 
-    void loadSuggested(int maxNumber, IControlsLoadCallback cb);
+    void loadSuggested(IControlsSubscriber subscriber);
 
     void subscribe(in List<String> controlIds,
              IControlsSubscriber subscriber);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 12f245e..9de1222 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -6012,7 +6012,13 @@
     @VisibleForTesting
     public class InsertionPointCursorController implements CursorController {
         private InsertionHandleView mHandle;
+        // Tracks whether the cursor is currently being dragged.
         private boolean mIsDraggingCursor;
+        // During a drag, tracks whether the user's finger has adjusted to be over the handle rather
+        // than the cursor bar.
+        private boolean mIsTouchSnappedToHandleDuringDrag;
+        // During a drag, tracks the line of text where the cursor was last positioned.
+        private int mPrevLineDuringDrag;
 
         public void onTouchEvent(MotionEvent event) {
             if (hasSelectionController() && getSelectionController().isCursorBeingModified()) {
@@ -6043,8 +6049,8 @@
         }
 
         private void positionCursorDuringDrag(MotionEvent event) {
-            int line = mTextView.getLineAtCoordinate(event.getY());
-            int offset = mTextView.getOffsetAtCoordinate(line, event.getX());
+            mPrevLineDuringDrag = getLineDuringDrag(event);
+            int offset = mTextView.getOffsetAtCoordinate(mPrevLineDuringDrag, event.getX());
             int oldSelectionStart = mTextView.getSelectionStart();
             int oldSelectionEnd = mTextView.getSelectionEnd();
             if (offset == oldSelectionStart && offset == oldSelectionEnd) {
@@ -6057,11 +6063,58 @@
             }
         }
 
+        /**
+         * Returns the line where the cursor should be positioned during a cursor drag. Rather than
+         * simply returning the line directly at the touch position, this function has the following
+         * additional logic:
+         * 1) Apply some slop to avoid switching lines if the touch moves just slightly off the
+         * current line.
+         * 2) Allow the user's finger to slide down and "snap" to the handle to provide better
+         * visibility of the cursor and text.
+         */
+        private int getLineDuringDrag(MotionEvent event) {
+            final Layout layout = mTextView.getLayout();
+            if (mTouchState.isOnHandle()) {
+                // The drag was initiated from the handle, so no need to apply the snap logic. See
+                // InsertionHandleView.touchThrough().
+                return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY());
+            }
+            if (mIsTouchSnappedToHandleDuringDrag) {
+                float cursorY = event.getY() - getHandle().getIdealVerticalOffset();
+                return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
+            }
+            int line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY());
+            if (mPrevLineDuringDrag == UNSET_LINE || line <= mPrevLineDuringDrag) {
+                // User's finger is on the same line or moving up; continue positioning the cursor
+                // directly at the touch location.
+                return line;
+            }
+            // User's finger is moving downwards; delay jumping to the lower line to allow the
+            // touch to move to the handle.
+            float cursorY = event.getY() - getHandle().getIdealVerticalOffset();
+            line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
+            if (line < mPrevLineDuringDrag) {
+                return mPrevLineDuringDrag;
+            }
+            // User's finger is now over the handle, at the ideal offset from the cursor. From now
+            // on, position the cursor higher up from the actual touch location so that the user's
+            // finger stays "snapped" to the handle. This provides better visibility of the text.
+            mIsTouchSnappedToHandleDuringDrag = true;
+            if (TextView.DEBUG_CURSOR) {
+                logCursor("InsertionPointCursorController",
+                        "snapped touch to handle: eventY=%d, cursorY=%d, mLastLine=%d, line=%d",
+                        (int) event.getY(), (int) cursorY, mPrevLineDuringDrag, line);
+            }
+            return line;
+        }
+
         private void startCursorDrag(MotionEvent event) {
             if (TextView.DEBUG_CURSOR) {
                 logCursor("InsertionPointCursorController", "start cursor drag");
             }
             mIsDraggingCursor = true;
+            mIsTouchSnappedToHandleDuringDrag = false;
+            mPrevLineDuringDrag = UNSET_LINE;
             // We don't want the parent scroll/long-press handlers to take over while dragging.
             mTextView.getParent().requestDisallowInterceptTouchEvent(true);
             mTextView.cancelLongPress();
@@ -6084,6 +6137,8 @@
                 logCursor("InsertionPointCursorController", "end cursor drag");
             }
             mIsDraggingCursor = false;
+            mIsTouchSnappedToHandleDuringDrag = false;
+            mPrevLineDuringDrag = UNSET_LINE;
             // Hide the magnifier and set the handle to be hidden after a delay.
             getHandle().dismissMagnifier();
             getHandle().hideAfterDelay();
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d91911c..e4141e0 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -105,10 +105,12 @@
 using namespace std::placeholders;
 
 using android::String8;
+using android::base::ReadFileToString;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 using android::base::GetBoolProperty;
+using android::base::GetProperty;
 
 #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
                               append(StringPrintf(__VA_ARGS__))
@@ -174,6 +176,12 @@
 static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
     "persist.zygote.app_data_isolation";
 
+/**
+ * Property to enable app data isolation for sdcard obb or data in vold.
+ */
+static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+    "persist.sys.vold_app_data_isolation_enabled";
+
 static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
 static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;
 
@@ -603,6 +611,15 @@
   }
 }
 
+static bool IsFilesystemSupported(const std::string& fsType) {
+    std::string supported;
+    if (!ReadFileToString("/proc/filesystems", &supported)) {
+        ALOGE("Failed to read supported filesystems");
+        return false;
+    }
+    return supported.find(fsType + "\n") != std::string::npos;
+}
+
 static void PreApplicationInit() {
   // The child process sets this to indicate it's not the zygote.
   android_mallopt(M_SET_ZYGOTE_CHILD, nullptr, 0);
@@ -782,6 +799,31 @@
   }
 }
 
+static void BindMountObbPackage(std::string_view package_name, int userId, fail_fn_t fail_fn) {
+
+  // TODO(148772775): Pass primary volume name from zygote argument to here
+  std::string source;
+  if (IsFilesystemSupported("sdcardfs")) {
+    source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s",
+        userId, package_name.data());
+  } else {
+    source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s",
+        userId, userId, package_name.data());
+  }
+  std::string target(
+      StringPrintf("/storage/emulated/%d/Android/obb/%s", userId, package_name.data()));
+
+  if (access(source.c_str(), F_OK) != 0) {
+    fail_fn(CREATE_ERROR("Cannot access source %s: %s", source.c_str(), strerror(errno)));
+  }
+
+  if (access(target.c_str(), F_OK) != 0) {
+    fail_fn(CREATE_ERROR("Cannot access target %s: %s", target.c_str(), strerror(errno)));
+  }
+
+  BindMount(source, target, fail_fn);
+}
+
 // Create a private mount namespace and bind mount appropriate emulated
 // storage for the given user.
 static void MountEmulatedStorage(uid_t uid, jint mount_mode,
@@ -1504,6 +1546,60 @@
   }
 }
 
+// Bind mount all obb directories that are visible to this app.
+// If app data isolation is not enabled for this process, bind mount the whole obb
+// directory instead.
+static void BindMountAppObbDirs(JNIEnv* env, jobjectArray pkg_data_info_list,
+    uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) {
+
+  auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+  const userid_t user_id = multiuser_get_user_id(uid);
+
+  // If FUSE is not ready for this user, skip it
+  // TODO(148772775): Pass primary volume name from zygote argument to here
+  std::string tmp = GetProperty("vold.fuse_running_users", "");
+  std::istringstream fuse_running_users(tmp);
+  bool user_found = false;
+  std::string s;
+  std::string user_id_str = std::to_string(user_id);
+  while (!user_found && std::getline(fuse_running_users, s, ',')) {
+    if (user_id_str == s) {
+      user_found = true;
+    }
+  }
+  if (!user_found) {
+    ALOGI("User %d is not running fuse yet, fuse_running_users=%s", user_id, tmp.c_str());
+    return;
+  }
+
+  // Fuse is ready, so we can start using fuse path.
+  int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
+
+  if (size == 0) {
+    // App data isolation is not enabled for this process, so we bind mount to whole obb/ dir.
+    std::string source;
+    if (IsFilesystemSupported("sdcardfs")) {
+      source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", user_id);
+    } else {
+      source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", user_id, user_id);
+    }
+    std::string target(StringPrintf("/storage/emulated/%d/Android/obb", user_id));
+
+    if (access(source.c_str(), F_OK) != 0) {
+      fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno)));
+    }
+    BindMount(source, target, fail_fn);
+    return;
+  }
+
+  // Bind mount each package obb directory
+  for (int i = 0; i < size; i += 3) {
+    jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
+    std::string packageName = extract_fn(package_str).value();
+    BindMountObbPackage(packageName, user_id, fail_fn);
+  }
+}
+
 // Utility routine to specialize a zygote child process.
 static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
                              jint runtime_flags, jobjectArray rlimits,
@@ -1552,6 +1648,12 @@
     isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
   }
 
+  if ((mount_external != MOUNT_EXTERNAL_INSTALLER) &&
+        GetBoolProperty(kPropFuse, false) &&
+        GetBoolProperty(ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
+    BindMountAppObbDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+  }
+
   // If this zygote isn't root, it won't be able to create a process group,
   // since the directory is owned by root.
   if (!is_system_server && getuid() == 0) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c9fb25e..62e57e4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1200,6 +1200,15 @@
                 android:description="@string/permdesc_acceptHandovers"
                 android:protectionLevel="dangerous" />
 
+    <!-- Allows an application assigned to the Dialer role to be granted access to the telephony
+         call audio streams, both TX and RX.
+         <p>Protection level: signature|appop
+    -->
+    <permission android:name="android.permission.ACCESS_CALL_AUDIO"
+                android.label="@string/permlab_accessCallAudio"
+                android:description="@string/permdesc_accessCallAudio"
+                android:protectionLevel="signature|appop" />
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device microphone                        -->
     <!-- ====================================================================== -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e6a93e5..d513e2b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5364,4 +5364,9 @@
     <string name="resolver_no_apps_available_explanation">We couldn\u2019t find any apps</string>
     <!-- Button which switches on the disabled work profile [CHAR LIMIT=NONE] -->
     <string name="resolver_switch_on_work">Switch on work</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permlab_accessCallAudio">Record or play audio in telephony calls</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_accessCallAudio">Allows this app, when assigned as default dialer application, to record or play audio in telephony calls.</string>
 </resources>
diff --git a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
index a24b4e0..78c88d7 100644
--- a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
+++ b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -62,8 +63,6 @@
     @Mock
     private IControlsActionCallback.Stub mActionCallback;
     @Mock
-    private IControlsLoadCallback.Stub mLoadCallback;
-    @Mock
     private IControlsSubscriber.Stub mSubscriber;
     @Mock
     private IIntentSender mIIntentSender;
@@ -79,8 +78,6 @@
 
         when(mActionCallback.asBinder()).thenCallRealMethod();
         when(mActionCallback.queryLocalInterface(any())).thenReturn(mActionCallback);
-        when(mLoadCallback.asBinder()).thenCallRealMethod();
-        when(mLoadCallback.queryLocalInterface(any())).thenReturn(mLoadCallback);
         when(mSubscriber.asBinder()).thenCallRealMethod();
         when(mSubscriber.queryLocalInterface(any())).thenReturn(mSubscriber);
 
@@ -102,22 +99,28 @@
         Control control2 = new Control.StatelessBuilder("TEST_ID_2", mPendingIntent)
                 .setDeviceType(DeviceTypes.TYPE_AIR_FRESHENER).build();
 
-        @SuppressWarnings("unchecked")
-        ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<IControlsSubscription.Stub> subscriptionCaptor =
+                ArgumentCaptor.forClass(IControlsSubscription.Stub.class);
+        ArgumentCaptor<Control> controlCaptor =
+                ArgumentCaptor.forClass(Control.class);
 
         ArrayList<Control> list = new ArrayList<>();
         list.add(control1);
         list.add(control2);
 
         mControlsProviderService.setControls(list);
-        mControlsProvider.load(mLoadCallback);
+        mControlsProvider.load(mSubscriber);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        verify(mLoadCallback).accept(eq(mToken), captor.capture());
-        List<Control> l = captor.getValue();
-        assertEquals(2, l.size());
-        assertTrue(equals(control1, l.get(0)));
-        assertTrue(equals(control2, l.get(1)));
+        verify(mSubscriber).onSubscribe(eq(mToken), subscriptionCaptor.capture());
+        subscriptionCaptor.getValue().request(1000);
+
+        verify(mSubscriber, times(2)).onNext(eq(mToken), controlCaptor.capture());
+        List<Control> values = controlCaptor.getAllValues();
+        assertTrue(equals(values.get(0), list.get(0)));
+        assertTrue(equals(values.get(1), list.get(1)));
+
+        verify(mSubscriber).onComplete(eq(mToken));
     }
 
     @Test
@@ -128,50 +131,57 @@
                 .build();
         Control statelessControl = new Control.StatelessBuilder(control).build();
 
-        @SuppressWarnings("unchecked")
-        ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<IControlsSubscription.Stub> subscriptionCaptor =
+                ArgumentCaptor.forClass(IControlsSubscription.Stub.class);
+        ArgumentCaptor<Control> controlCaptor =
+                ArgumentCaptor.forClass(Control.class);
 
         ArrayList<Control> list = new ArrayList<>();
         list.add(control);
 
         mControlsProviderService.setControls(list);
-        mControlsProvider.load(mLoadCallback);
+        mControlsProvider.load(mSubscriber);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        verify(mLoadCallback).accept(eq(mToken), captor.capture());
-        List<Control> l = captor.getValue();
-        assertEquals(1, l.size());
-        assertFalse(equals(control, l.get(0)));
-        assertTrue(equals(statelessControl, l.get(0)));
-        assertEquals(Control.STATUS_UNKNOWN, l.get(0).getStatus());
+        verify(mSubscriber).onSubscribe(eq(mToken), subscriptionCaptor.capture());
+        subscriptionCaptor.getValue().request(1000);
+
+        verify(mSubscriber).onNext(eq(mToken), controlCaptor.capture());
+        Control c = controlCaptor.getValue();
+        assertFalse(equals(control, c));
+        assertTrue(equals(statelessControl, c));
+        assertEquals(Control.STATUS_UNKNOWN, c.getStatus());
+
+        verify(mSubscriber).onComplete(eq(mToken));
     }
 
     @Test
-    public void testLoadSuggested_withMaxNumber() throws RemoteException {
+    public void testOnLoadSuggested_allStateless() throws RemoteException {
         Control control1 = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build();
         Control control2 = new Control.StatelessBuilder("TEST_ID_2", mPendingIntent)
                 .setDeviceType(DeviceTypes.TYPE_AIR_FRESHENER).build();
 
-        @SuppressWarnings("unchecked")
-        ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<IControlsSubscription.Stub> subscriptionCaptor =
+                ArgumentCaptor.forClass(IControlsSubscription.Stub.class);
+        ArgumentCaptor<Control> controlCaptor =
+                ArgumentCaptor.forClass(Control.class);
 
         ArrayList<Control> list = new ArrayList<>();
         list.add(control1);
         list.add(control2);
 
-        final int maxSuggested = 1;
-
         mControlsProviderService.setControls(list);
-        mControlsProvider.loadSuggested(maxSuggested, mLoadCallback);
+        mControlsProvider.loadSuggested(mSubscriber);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        verify(mLoadCallback).accept(eq(mToken), captor.capture());
-        List<Control> l = captor.getValue();
-        assertEquals(maxSuggested, l.size());
+        verify(mSubscriber).onSubscribe(eq(mToken), subscriptionCaptor.capture());
+        subscriptionCaptor.getValue().request(1);
 
-        for (int i = 0; i < maxSuggested; ++i) {
-            assertTrue(equals(list.get(i), l.get(i)));
-        }
+        verify(mSubscriber).onNext(eq(mToken), controlCaptor.capture());
+        Control c = controlCaptor.getValue();
+        assertTrue(equals(c, list.get(0)));
+
+        verify(mSubscriber).onComplete(eq(mToken));
     }
 
     @Test
@@ -244,22 +254,19 @@
         }
 
         @Override
-        public void loadSuggestedControls(int maxNumber, Consumer<List<Control>> cb) {
-            cb.accept(mControls);
-        }
-
-        @Override
         public Publisher<Control> publisherFor(List<String> ids) {
             return new Publisher<Control>() {
                 public void subscribe(final Subscriber s) {
-                    s.onSubscribe(new Subscription() {
-                            public void request(long n) {
-                                for (Control c : mControls) {
-                                    s.onNext(c);
-                                }
-                            }
-                            public void cancel() {}
-                        });
+                    s.onSubscribe(createSubscription(s, mControls));
+                }
+            };
+        }
+
+        @Override
+        public Publisher<Control> publisherForSuggested() {
+            return new Publisher<Control>() {
+                public void subscribe(final Subscriber s) {
+                    s.onSubscribe(createSubscription(s, mControls));
                 }
             };
         }
@@ -269,7 +276,19 @@
                 Consumer<Integer> cb) {
             cb.accept(ControlAction.RESPONSE_OK);
         }
+
+        private Subscription createSubscription(Subscriber s, List<Control> controls) {
+            return new Subscription() {
+                public void request(long n) {
+                    int i = 0;
+                    for (Control c : mControls) {
+                        if (i++ < n) s.onNext(c);
+                        else break;
+                    }
+                    s.onComplete();
+                }
+                public void cancel() {}
+            };
+        }
     }
 }
-
-
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index a602fa3..d7abfcc 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -25,6 +25,9 @@
 import static androidx.test.espresso.action.ViewActions.replaceText;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import static org.hamcrest.Matchers.emptyString;
 import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertFalse;
@@ -32,11 +35,14 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.text.Layout;
+import android.util.Log;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -50,9 +56,15 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.atomic.AtomicLong;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class EditorCursorDragTest {
+    private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName();
+
+    private static final AtomicLong sTicker = new AtomicLong(1);
+
     @Rule
     public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
             TextViewActivity.class);
@@ -119,13 +131,11 @@
         onView(withId(R.id.textview)).perform(replaceText(text));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
 
-        // Swipe along a diagonal path. This should drag the cursor.
-        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
-        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("2")));
-
-        // Swipe along a steeper diagonal path. This should still drag the cursor.
+        // Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
+        // the handle as the touch moves downwards (and because we have some slop to avoid jumping
+        // across lines), the cursor position will end up higher than the finger position.
         onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
-        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("3")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
 
         // Swipe right-down along a very steep diagonal path. This should not drag the cursor.
         // Normally this would trigger a scroll, but since the full view fits on the screen there
@@ -133,12 +143,15 @@
         onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("7")));
         onView(withId(R.id.textview)).check(hasSelection(not(emptyString())));
 
+        // Tap to clear the selection.
+        int index = text.indexOf("line9");
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index));
+        onView(withId(R.id.textview)).check(hasSelection(emptyString()));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
+
         // Swipe right-up along a very steep diagonal path. This should not drag the cursor.
         // Normally this would trigger a scroll, but since the full view fits on the screen there
         // is nothing to scroll and the gesture will trigger a selection drag.
-        int index = text.indexOf("line9");
-        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index));
-        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
         onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line7"), text.indexOf("1")));
         onView(withId(R.id.textview)).check(hasSelection(not(emptyString())));
     }
@@ -154,13 +167,11 @@
         onView(withId(R.id.textview)).perform(replaceText(text));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
 
-        // Swipe along a diagonal path. This should drag the cursor.
-        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
-        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("2")));
-
-        // Swipe along a steeper diagonal path. This should still drag the cursor.
+        // Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
+        // the handle as the touch moves downwards (and because we have some slop to avoid jumping
+        // across lines), the cursor position will end up higher than the finger position.
         onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
-        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("3")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
 
         // Swipe right-down along a very steep diagonal path. This should not drag the cursor.
         // Normally this would trigger a scroll up, but since the view is already at the top there
@@ -168,11 +179,14 @@
         onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("7")));
         onView(withId(R.id.textview)).check(hasSelection(not(emptyString())));
 
-        // Swipe right-up along a very steep diagonal path. This should not drag the cursor. This
-        // will trigger a downward scroll and the cursor position will not change.
+        // Tap to clear the selection.
         int index = text.indexOf("line9");
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index));
+        onView(withId(R.id.textview)).check(hasSelection(emptyString()));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
+
+        // Swipe right-up along a very steep diagonal path. This should not drag the cursor. This
+        // will trigger a downward scroll and the cursor position will not change.
         onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line7"), text.indexOf("1")));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
     }
@@ -387,12 +401,14 @@
         assertFalse(editor.getSelectionController().isCursorBeingModified());
     }
 
+    @Suppress // b/149712851
     @Test // Reproduces b/147366705
     public void testCursorDrag_nonSelectableTextView() throws Throwable {
         String text = "Hello world!";
         TextView tv = mActivity.findViewById(R.id.nonselectable_textview);
         tv.setText(text);
         Editor editor = tv.getEditorForTesting();
+        assertThat(editor).isNotNull();
 
         // Simulate a tap. No error should be thrown.
         long event1Time = 1001;
@@ -404,6 +420,68 @@
                 dragOnText(text.indexOf("llo"), text.indexOf("!")));
     }
 
+    @Test
+    public void testCursorDrag_slop() throws Throwable {
+        String text = "line1: This is the 1st line: A\n"
+                    + "line2: This is the 2nd line: B\n"
+                    + "line3: This is the 3rd line: C\n";
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+        TextView tv = mActivity.findViewById(R.id.textview);
+
+        // Simulate a drag where the finger moves slightly up and down (above and below the original
+        // line where the drag started). The cursor should just move along the original line without
+        // jumping up or down across lines.
+        MotionEventInfo[] events = new MotionEventInfo[]{
+                // Start dragging along the second line
+                motionEventInfo(text.indexOf("line2"), 1.0f),
+                motionEventInfo(text.indexOf("This is the 2nd"), 1.0f),
+                // Move to the bottom of the first line; cursor should remain on second line
+                motionEventInfo(text.indexOf("he 1st"), 0.0f, text.indexOf("he 2nd")),
+                // Move to the top of the third line; cursor should remain on second line
+                motionEventInfo(text.indexOf("e: C"), 1.0f, text.indexOf("e: B")),
+                motionEventInfo(text.indexOf("B"), 0.0f)
+        };
+        simulateDrag(tv, events, true);
+    }
+
+    @Test
+    public void testCursorDrag_snapToHandle() throws Throwable {
+        String text = "line1: This is the 1st line: A\n"
+                    + "line2: This is the 2nd line: B\n"
+                    + "line3: This is the 3rd line: C\n";
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+        TextView tv = mActivity.findViewById(R.id.textview);
+
+        // When the drag motion moves downward, we delay jumping to the lower line to allow the
+        // user's touch to snap to the cursor's handle. Once the finger is over the handle, we
+        // position the cursor above the user's actual touch (offset such that the finger remains
+        // over the handle rather than on top of the cursor vertical bar). This improves the
+        // visibility of the cursor and the text underneath.
+        MotionEventInfo[] events = new MotionEventInfo[]{
+                // Start dragging along the first line
+                motionEventInfo(text.indexOf("line1"), 1.0f),
+                motionEventInfo(text.indexOf("This is the 1st"), 1.0f),
+                // Move to the bottom of the third line; cursor should end up on second line
+                motionEventInfo(text.indexOf("he 3rd"), 0.0f, text.indexOf("he 2nd")),
+                // Move to the middle of the second line; cursor should end up on the first line
+                motionEventInfo(text.indexOf("he 2nd"), 0.5f, text.indexOf("he 1st"))
+        };
+        simulateDrag(tv, events, true);
+
+        // If the drag motion hasn't moved downward (ie, we haven't had a chance to snap to the
+        // handle), we position the cursor directly at the touch position.
+        events = new MotionEventInfo[]{
+                // Start dragging along the third line
+                motionEventInfo(text.indexOf("line3"), 1.0f),
+                motionEventInfo(text.indexOf("This is the 3rd"), 1.0f),
+                // Move to the middle of the second line; cursor should end up on the second line
+                motionEventInfo(text.indexOf("he 2nd"), 0.5f, text.indexOf("he 2nd")),
+        };
+        simulateDrag(tv, events, true);
+    }
+
     private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
         return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
     }
@@ -436,4 +514,89 @@
         event.setButtonState(MotionEvent.BUTTON_PRIMARY);
         return event;
     }
+
+    public static MotionEventInfo motionEventInfo(int index, float ratioToLineTop) {
+        return new MotionEventInfo(index, ratioToLineTop, index);
+    }
+
+    public static MotionEventInfo motionEventInfo(int index, float ratioToLineTop,
+            int expectedCursorIndex) {
+        return new MotionEventInfo(index, ratioToLineTop, expectedCursorIndex);
+    }
+
+    private static class MotionEventInfo {
+        public final int index;
+        public final float ratioToLineTop; // 0.0 = bottom of line, 0.5 = middle of line, etc
+        public final int expectedCursorIndex;
+
+        private MotionEventInfo(int index, float ratioToLineTop, int expectedCursorIndex) {
+            this.index = index;
+            this.ratioToLineTop = ratioToLineTop;
+            this.expectedCursorIndex = expectedCursorIndex;
+        }
+
+        public float[] getCoordinates(TextView textView) {
+            Layout layout = textView.getLayout();
+            int line = layout.getLineForOffset(index);
+            float x = layout.getPrimaryHorizontal(index) + textView.getTotalPaddingLeft();
+            int bottom = layout.getLineBottom(line);
+            int top = layout.getLineTop(line);
+            float y = bottom - ((bottom - top) * ratioToLineTop) + textView.getTotalPaddingTop();
+            return new float[]{x, y};
+        }
+    }
+
+    private void simulateDrag(TextView tv, MotionEventInfo[] events, boolean runAssertions)
+            throws Exception {
+        Editor editor = tv.getEditorForTesting();
+
+        float[] downCoords = events[0].getCoordinates(tv);
+        long downEventTime = sTicker.addAndGet(10_000);
+        MotionEvent downEvent = downEvent(downEventTime, downEventTime,
+                downCoords[0], downCoords[1]);
+        mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(downEvent));
+
+        for (int i = 1; i < events.length; i++) {
+            float[] moveCoords = events[i].getCoordinates(tv);
+            long eventTime = downEventTime + i;
+            MotionEvent event = moveEvent(downEventTime, eventTime, moveCoords[0], moveCoords[1]);
+            mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event));
+            assertCursorPosition(tv, events[i].expectedCursorIndex, runAssertions);
+        }
+
+        MotionEventInfo lastEvent = events[events.length - 1];
+        float[] upCoords = lastEvent.getCoordinates(tv);
+        long upEventTime = downEventTime + events.length;
+        MotionEvent upEvent = upEvent(downEventTime, upEventTime, upCoords[0], upCoords[1]);
+        mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(upEvent));
+    }
+
+    private static void assertCursorPosition(TextView tv, int expectedPosition,
+            boolean runAssertions) {
+        String textAfterExpectedPos = getTextAfterIndex(tv, expectedPosition, 15);
+        String textAfterActualPos = getTextAfterIndex(tv, tv.getSelectionStart(), 15);
+        String msg = "Expected cursor at " + expectedPosition + ", just before \""
+                + textAfterExpectedPos + "\". Cursor is at " + tv.getSelectionStart()
+                + ", just before \"" + textAfterActualPos + "\".";
+        Log.d(LOG_TAG, msg);
+        if (runAssertions) {
+            assertWithMessage(msg).that(tv.getSelectionStart()).isEqualTo(expectedPosition);
+            assertThat(tv.getSelectionEnd()).isEqualTo(expectedPosition);
+        }
+    }
+
+    private static String getTextAfterIndex(TextView tv, int position, int maxLength) {
+        int end = Math.min(position + maxLength, tv.getText().length());
+        try {
+            String afterPosition = tv.getText().subSequence(position, end).toString();
+            if (afterPosition.indexOf('\n') > 0) {
+                afterPosition = afterPosition.substring(0, afterPosition.indexOf('\n'));
+            }
+            return afterPosition;
+        } catch (StringIndexOutOfBoundsException e) {
+            Log.d(LOG_TAG, "Invalid target position: position=" + position + ", length="
+                    + tv.getText().length() + ", end=" + end);
+            return "";
+        }
+    }
 }
diff --git a/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java
index dfcaf81..b2f9a0f 100644
--- a/location/java/android/location/GnssAntennaInfo.java
+++ b/location/java/android/location/GnssAntennaInfo.java
@@ -16,72 +16,37 @@
 
 package android.location;
 
-import android.annotation.IntDef;
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A class that contains information about a GNSS antenna. GNSS antenna characteristics can change
  * with device configuration, such as when a device is folded open or closed. Antenna information is
- * delivered to registered instances of {@link Callback}.
+ * delivered to registered instances of {@link Listener}.
  */
 public final class GnssAntennaInfo implements Parcelable {
     private final double mCarrierFrequencyMHz;
-    private final PhaseCenterOffsetCoordinates mPhaseCenterOffsetCoordinates;
-    private final PhaseCenterVariationCorrections mPhaseCenterVariationCorrections;
-    private final SignalGainCorrections mSignalGainCorrections;
+    private final PhaseCenterOffset mPhaseCenterOffset;
+    private final SphericalCorrections mPhaseCenterVariationCorrections;
+    private final SphericalCorrections mSignalGainCorrections;
 
     /**
      * Used for receiving GNSS antenna info from the GNSS engine. You can implement this interface
-     * and call {@link LocationManager#registerAntennaInfoCallback};
+     * and call {@link LocationManager#registerAntennaInfoListener};
      */
-    public abstract static class Callback {
+    public interface Listener {
         /**
-         * The status of GNSS antenna info.
-         *
-         * @hide
-         */
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED})
-        public @interface GnssAntennaInfoStatus {
-        }
-
-        /**
-         * The system does not support GNSS antenna info.
-         *
-         * This status will not change in the future.
-         */
-        public static final int STATUS_NOT_SUPPORTED = 0;
-
-        /**
-         * GNSS antenna info updates are being successfully tracked.
-         */
-        public static final int STATUS_READY = 1;
-
-        /**
-         * GNSS provider or Location is disabled, updated will not be received until they are
-         * enabled.
-         */
-        public static final int STATUS_LOCATION_DISABLED = 2;
-
-        /**
-         * Returns the latest GNSS antenna info. This event is triggered when a callback is
+         * Returns the latest GNSS antenna info. This event is triggered when a listener is
          * registered, and whenever the antenna info changes (due to a device configuration change).
          */
-        public void onGnssAntennaInfoReceived(@NonNull List<GnssAntennaInfo> gnssAntennaInfos) {}
-
-        /**
-         * Returns the latest status of the GNSS antenna info sub-system.
-         */
-        public void onStatusChanged(@GnssAntennaInfoStatus int status) {}
+        void onGnssAntennaInfoReceived(@NonNull List<GnssAntennaInfo> gnssAntennaInfos);
     }
 
     /**
@@ -90,37 +55,31 @@
      * for mobiles - see sensor or form factor documents for details. Uncertainties are reported
      *  to 1-sigma.
      */
-    public static final class PhaseCenterOffsetCoordinates implements Parcelable {
-        private final double mPhaseCenterOffsetCoordinateXMillimeters;
-        private final double mPhaseCenterOffsetCoordinateXUncertaintyMillimeters;
-        private final double mPhaseCenterOffsetCoordinateYMillimeters;
-        private final double mPhaseCenterOffsetCoordinateYUncertaintyMillimeters;
-        private final double mPhaseCenterOffsetCoordinateZMillimeters;
-        private final double mPhaseCenterOffsetCoordinateZUncertaintyMillimeters;
+    public static final class PhaseCenterOffset implements Parcelable {
+        private final double mOffsetXMm;
+        private final double mOffsetXUncertaintyMm;
+        private final double mOffsetYMm;
+        private final double mOffsetYUncertaintyMm;
+        private final double mOffsetZMm;
+        private final double mOffsetZUncertaintyMm;
 
-        @VisibleForTesting
-        public PhaseCenterOffsetCoordinates(double phaseCenterOffsetCoordinateXMillimeters,
-                double phaseCenterOffsetCoordinateXUncertaintyMillimeters,
-                double phaseCenterOffsetCoordinateYMillimeters,
-                double phaseCenterOffsetCoordinateYUncertaintyMillimeters,
-                double phaseCenterOffsetCoordinateZMillimeters,
-                double phaseCenterOffsetCoordinateZUncertaintyMillimeters) {
-            mPhaseCenterOffsetCoordinateXMillimeters = phaseCenterOffsetCoordinateXMillimeters;
-            mPhaseCenterOffsetCoordinateYMillimeters = phaseCenterOffsetCoordinateYMillimeters;
-            mPhaseCenterOffsetCoordinateZMillimeters = phaseCenterOffsetCoordinateZMillimeters;
-            mPhaseCenterOffsetCoordinateXUncertaintyMillimeters =
-                    phaseCenterOffsetCoordinateXUncertaintyMillimeters;
-            mPhaseCenterOffsetCoordinateYUncertaintyMillimeters =
-                    phaseCenterOffsetCoordinateYUncertaintyMillimeters;
-            mPhaseCenterOffsetCoordinateZUncertaintyMillimeters =
-                    phaseCenterOffsetCoordinateZUncertaintyMillimeters;
+        public PhaseCenterOffset(
+                double offsetXMm, double offsetXUncertaintyMm,
+                double offsetYMm, double offsetYUncertaintyMm,
+                double offsetZMm, double offsetZUncertaintyMm) {
+            mOffsetXMm = offsetXMm;
+            mOffsetYMm = offsetYMm;
+            mOffsetZMm = offsetZMm;
+            mOffsetXUncertaintyMm = offsetXUncertaintyMm;
+            mOffsetYUncertaintyMm = offsetYUncertaintyMm;
+            mOffsetZUncertaintyMm = offsetZUncertaintyMm;
         }
 
-        public static final @NonNull Creator<PhaseCenterOffsetCoordinates> CREATOR =
-                new Creator<PhaseCenterOffsetCoordinates>() {
+        public static final @NonNull Creator<PhaseCenterOffset> CREATOR =
+                new Creator<PhaseCenterOffset>() {
                     @Override
-                    public PhaseCenterOffsetCoordinates createFromParcel(Parcel in) {
-                        return new PhaseCenterOffsetCoordinates(
+                    public PhaseCenterOffset createFromParcel(Parcel in) {
+                        return new PhaseCenterOffset(
                                 in.readDouble(),
                                 in.readDouble(),
                                 in.readDouble(),
@@ -131,33 +90,39 @@
                     }
 
                     @Override
-                    public PhaseCenterOffsetCoordinates[] newArray(int size) {
-                        return new PhaseCenterOffsetCoordinates[size];
+                    public PhaseCenterOffset[] newArray(int size) {
+                        return new PhaseCenterOffset[size];
                     }
                 };
 
-        public double getXCoordMillimeters() {
-            return mPhaseCenterOffsetCoordinateXMillimeters;
+        @FloatRange()
+        public double getXOffsetMm() {
+            return mOffsetXMm;
         }
 
-        public double getXCoordUncertaintyMillimeters() {
-            return mPhaseCenterOffsetCoordinateXUncertaintyMillimeters;
+        @FloatRange()
+        public double getXOffsetUncertaintyMm() {
+            return mOffsetXUncertaintyMm;
         }
 
-        public double getYCoordMillimeters() {
-            return mPhaseCenterOffsetCoordinateYMillimeters;
+        @FloatRange()
+        public double getYOffsetMm() {
+            return mOffsetYMm;
         }
 
-        public double getYCoordUncertaintyMillimeters() {
-            return mPhaseCenterOffsetCoordinateYUncertaintyMillimeters;
+        @FloatRange()
+        public double getYOffsetUncertaintyMm() {
+            return mOffsetYUncertaintyMm;
         }
 
-        public double getZCoordMillimeters() {
-            return mPhaseCenterOffsetCoordinateZMillimeters;
+        @FloatRange()
+        public double getZOffsetMm() {
+            return mOffsetZMm;
         }
 
-        public double getZCoordUncertaintyMillimeters() {
-            return mPhaseCenterOffsetCoordinateZUncertaintyMillimeters;
+        @FloatRange()
+        public double getZOffsetUncertaintyMm() {
+            return mOffsetZUncertaintyMm;
         }
 
         @Override
@@ -167,30 +132,27 @@
 
         @Override
         public void writeToParcel(@NonNull Parcel dest, int flags) {
-            dest.writeDouble(mPhaseCenterOffsetCoordinateXMillimeters);
-            dest.writeDouble(mPhaseCenterOffsetCoordinateXUncertaintyMillimeters);
-            dest.writeDouble(mPhaseCenterOffsetCoordinateYMillimeters);
-            dest.writeDouble(mPhaseCenterOffsetCoordinateYUncertaintyMillimeters);
-            dest.writeDouble(mPhaseCenterOffsetCoordinateZMillimeters);
-            dest.writeDouble(mPhaseCenterOffsetCoordinateZUncertaintyMillimeters);
+            dest.writeDouble(mOffsetXMm);
+            dest.writeDouble(mOffsetXUncertaintyMm);
+            dest.writeDouble(mOffsetYMm);
+            dest.writeDouble(mOffsetYUncertaintyMm);
+            dest.writeDouble(mOffsetZMm);
+            dest.writeDouble(mOffsetZUncertaintyMm);
         }
 
         @Override
         public String toString() {
-            StringBuilder builder = new StringBuilder("PhaseCenteroffset:\n");
-            builder.append("X: " + mPhaseCenterOffsetCoordinateXMillimeters + " +/- "
-                    + mPhaseCenterOffsetCoordinateXUncertaintyMillimeters + "\n");
-            builder.append("Y: " + mPhaseCenterOffsetCoordinateYMillimeters + " +/- "
-                    + mPhaseCenterOffsetCoordinateYUncertaintyMillimeters + "\n");
-            builder.append("Z: " + mPhaseCenterOffsetCoordinateZMillimeters + " +/- "
-                    + mPhaseCenterOffsetCoordinateZUncertaintyMillimeters + "\n");
-            return builder.toString();
+            return "PhaseCenterOffset{"
+                    + "OffsetXMm=" + mOffsetXMm + " +/-" + mOffsetXUncertaintyMm
+                    + ", OffsetYMm=" + mOffsetYMm + " +/-" + mOffsetYUncertaintyMm
+                    + ", OffsetZMm=" + mOffsetZMm + " +/-" + mOffsetZUncertaintyMm
+                    + '}';
         }
     }
 
     /**
-     * Class containing information about the phase center variation (PCV) corrections. The PCV
-     * correction is added to the phase measurement to obtain the corrected value.
+     * Represents corrections on a spherical mapping. Corrections are added to measurements to
+     * obtain the corrected values.
      *
      * The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays.
      *
@@ -203,229 +165,7 @@
      * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
      * i.e., deltaPhi = 180 / (number of columns - 1).
      */
-    public static final class PhaseCenterVariationCorrections extends SphericalCorrections {
-
-        @VisibleForTesting
-        public PhaseCenterVariationCorrections(
-                @NonNull double[][] phaseCenterVariationCorrectionsMillimeters,
-                @NonNull double[][] phaseCenterVariationCorrectionUncertaintiesMillimeters) {
-            super(phaseCenterVariationCorrectionsMillimeters,
-                    phaseCenterVariationCorrectionUncertaintiesMillimeters);
-        }
-
-        private PhaseCenterVariationCorrections(@NonNull Parcel in) {
-            super(in);
-        }
-
-        /**
-         * Get the phase center variation correction in millimeters at the specified row and column
-         * in the underlying 2D array.
-         * @param row zero-based major index in the array
-         * @param column zero-based minor index in the array
-         * @return phase center correction in millimeters
-         */
-        public double getPhaseCenterVariationCorrectionMillimetersAt(int row, int column) {
-            return super.getCorrectionAt(row, column);
-        }
-
-        /**
-         * Get the phase center variation correction uncertainty in millimeters at the specified row
-         * and column in the underlying 2D array.
-         * @param row zero-based major index in the array
-         * @param column zero-based minor index in the array
-         * @return 1-sigma phase center correction uncertainty in millimeters
-         */
-        public double getPhaseCenterVariationCorrectionUncertaintyMillimetersAt(
-                int row, int column) {
-            return super.getCorrectionUncertaintyAt(row, column);
-        }
-
-        public @NonNull double[][] getRawCorrectionsArray() {
-            return super.getRawCorrectionsArray().clone();
-        }
-
-        public @NonNull double[][] getRawCorrectionUncertaintiesArray() {
-            return super.getRawCorrectionUncertaintiesArray().clone();
-        }
-
-        public int getNumRows() {
-            return super.getNumRows();
-        }
-
-        public int getNumColumns() {
-            return super.getNumColumns();
-        }
-
-        /**
-         * The fixed theta angle separation between successive rows.
-         */
-        public double getDeltaTheta() {
-            return super.getDeltaTheta();
-        }
-
-        /**
-         * The fixed phi angle separation between successive columns.
-         */
-        public double getDeltaPhi() {
-            return super.getDeltaPhi();
-        }
-
-        public static final @NonNull Creator<PhaseCenterVariationCorrections> CREATOR =
-                new Creator<PhaseCenterVariationCorrections>() {
-                    @Override
-                    public PhaseCenterVariationCorrections createFromParcel(Parcel in) {
-                        return new PhaseCenterVariationCorrections(in);
-                    }
-
-                    @Override
-                    public PhaseCenterVariationCorrections[] newArray(int size) {
-                        return new PhaseCenterVariationCorrections[size];
-                    }
-                };
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(@NonNull Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder("PhaseCenterVariationCorrections:\n");
-            builder.append(super.toString());
-            return builder.toString();
-        }
-    }
-
-    /**
-     * Class containing information about the signal gain (SG) corrections. The SG
-     * correction is added to the signal gain to obtain the corrected value.
-     *
-     * The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays.
-     *
-     * Each row (major indices) represents a fixed theta. The first row corresponds to a
-     * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
-     * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta
-     * = 360 / (number of rows).
-     *
-     * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending
-     * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
-     * i.e., deltaPhi = 180 / (number of columns - 1).
-     */
-    public static final class SignalGainCorrections extends SphericalCorrections {
-
-        @VisibleForTesting
-        public SignalGainCorrections(
-                @NonNull double[][] signalGainCorrectionsDbi,
-                @NonNull double[][] signalGainCorrectionUncertaintiesDbi) {
-            super(signalGainCorrectionsDbi,
-                    signalGainCorrectionUncertaintiesDbi);
-        }
-
-        private SignalGainCorrections(@NonNull Parcel in) {
-            super(in);
-        }
-
-        /**
-         * Get the signal gain correction in dbi at the specified row and column
-         * in the underlying 2D array.
-         * @param row zero-based major index in the array
-         * @param column zero-based minor index in the array
-         * @return signal gain correction in dbi
-         */
-        public double getSignalGainCorrectionDbiAt(int row, int column) {
-            return super.getCorrectionAt(row, column);
-        }
-
-        /**
-         * Get the signal gain correction correction uncertainty in dbi at the specified row
-         * and column in the underlying 2D array.
-         * @param row zero-based major index in the array
-         * @param column zero-based minor index in the array
-         * @return 1-sigma signal gain correction uncertainty in dbi
-         */
-        public double getSignalGainCorrectionUncertaintyDbiAt(int row, int column) {
-            return super.getCorrectionUncertaintyAt(row, column);
-        }
-
-        public @NonNull double[][] getRawCorrectionsArray() {
-            return super.getRawCorrectionsArray().clone();
-        }
-
-        public @NonNull double[][] getRawCorrectionUncertaintiesArray() {
-            return super.getRawCorrectionUncertaintiesArray().clone();
-        }
-
-        public int getNumRows() {
-            return super.getNumRows();
-        }
-
-        public int getNumColumns() {
-            return super.getNumColumns();
-        }
-
-        /**
-         * The fixed theta angle separation between successive rows.
-         */
-        public double getDeltaTheta() {
-            return super.getDeltaTheta();
-        }
-
-        /**
-         * The fixed phi angle separation between successive columns.
-         */
-        public double getDeltaPhi() {
-            return super.getDeltaPhi();
-        }
-
-        public static final @NonNull Creator<SignalGainCorrections> CREATOR =
-                new Creator<SignalGainCorrections>() {
-                    @Override
-                    public SignalGainCorrections createFromParcel(Parcel in) {
-                        return new SignalGainCorrections(in);
-                    }
-
-                    @Override
-                    public SignalGainCorrections[] newArray(int size) {
-                        return new SignalGainCorrections[size];
-                    }
-                };
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(@NonNull Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder("SignalGainCorrections:\n");
-            builder.append(super.toString());
-            return builder.toString();
-        }
-    }
-
-    /**
-     * Represents corrections on a spherical mapping.
-     *
-     * Each row (major indices) represents a fixed theta. The first row corresponds to a
-     * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
-     * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta
-     * = 360 / (number of rows).
-     *
-     * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending
-     * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
-     * i.e., deltaPhi = 180 / (number of columns - 1).
-     */
-    private abstract static class SphericalCorrections implements Parcelable {
+    public static final class SphericalCorrections implements Parcelable{
         private final double[][] mCorrections;
         private final double[][] mCorrectionUncertainties;
         private final double mDeltaTheta;
@@ -433,7 +173,7 @@
         private final int mNumRows;
         private final int mNumColumns;
 
-        SphericalCorrections(@NonNull double[][] corrections,
+        public SphericalCorrections(@NonNull double[][] corrections,
                 @NonNull double[][] correctionUncertainties) {
             if (corrections.length != correctionUncertainties.length
                     || corrections[0].length != correctionUncertainties[0].length) {
@@ -474,54 +214,84 @@
                 in.readDoubleArray(correctionUncertainties[row]);
             }
 
-            mNumRows = corrections.length;
-            mNumColumns = corrections[0].length;
+            mNumRows = numRows;
+            mNumColumns = numColumns;
             mCorrections = corrections;
             mCorrectionUncertainties = correctionUncertainties;
             mDeltaTheta = 360.0d / mNumRows;
             mDeltaPhi = 180.0d / (mNumColumns - 1);
         }
 
-        private double getCorrectionAt(int row, int column) {
-            return mCorrections[row][column];
-        }
-
-        private double getCorrectionUncertaintyAt(int row, int column) {
-            return mCorrectionUncertainties[row][column];
-        }
-
+        /**
+         * Array representing corrections on a spherical mapping. Corrections are added to
+         * measurements to obtain the corrected values.
+         *
+         * Each row (major indices) represents a fixed theta. The first row corresponds to a
+         * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
+         * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e.,
+         * deltaTheta = 360 / (number of rows).
+         *
+         * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and
+         * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith
+         * angles, i.e., deltaPhi = 180 / (number of columns - 1).
+         */
         @NonNull
-        private double[][] getRawCorrectionsArray() {
+        public double[][] getCorrectionsArray() {
             return mCorrections;
         }
 
+        /**
+         * Array representing uncertainty on corrections on a spherical mapping.
+         *
+         * Each row (major indices) represents a fixed theta. The first row corresponds to a
+         * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
+         * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e.,
+         * deltaTheta = 360 / (number of rows).
+         *
+         * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and
+         * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith
+         * angles, i.e., deltaPhi = 180 / (number of columns - 1).
+         */
         @NonNull
-        private double[][] getRawCorrectionUncertaintiesArray() {
+        public double[][] getCorrectionUncertaintiesArray() {
             return mCorrectionUncertainties;
         }
 
-        private int getNumRows() {
-            return mNumRows;
-        }
-
-        private int getNumColumns() {
-            return mNumColumns;
-        }
-
         /**
          * The fixed theta angle separation between successive rows.
          */
-        private double getDeltaTheta() {
+        @FloatRange(from = 0.0f, to = 360.0f)
+        public double getDeltaTheta() {
             return mDeltaTheta;
         }
 
         /**
          * The fixed phi angle separation between successive columns.
          */
-        private double getDeltaPhi() {
+        @FloatRange(from = 0.0f, to = 180.0f)
+        public double getDeltaPhi() {
             return mDeltaPhi;
         }
 
+
+        public static final @NonNull Creator<SphericalCorrections> CREATOR =
+                new Creator<SphericalCorrections>() {
+                    @Override
+                    public SphericalCorrections createFromParcel(Parcel in) {
+                        return new SphericalCorrections(in);
+                    }
+
+                    @Override
+                    public SphericalCorrections[] newArray(int size) {
+                        return new SphericalCorrections[size];
+                    }
+                };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
         @Override
         public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeInt(mNumRows);
@@ -534,62 +304,114 @@
             }
         }
 
-        private String arrayToString(double[][] array) {
-            StringBuilder builder = new StringBuilder();
-            for (int row = 0; row < mNumRows; row++) {
-                builder.append("[ ");
-                for (int column = 0; column < mNumColumns - 1; column++) {
-                    builder.append(array[row][column] + ", ");
-                }
-                builder.append(array[row][mNumColumns - 1] + " ]\n");
-            }
-            return builder.toString();
-        }
-
         @Override
         public String toString() {
-            StringBuilder builder = new StringBuilder();
-            builder.append("DeltaTheta: " + mDeltaTheta + "\n");
-            builder.append("DeltaPhi: " + mDeltaPhi + "\n");
-            builder.append("CorrectionsArray:\n");
-            builder.append(arrayToString(mCorrections));
-            builder.append("CorrectionUncertaintiesArray:\n");
-            builder.append(arrayToString(mCorrectionUncertainties));
-            return builder.toString();
+            return "SphericalCorrections{"
+                    + "Corrections=" + Arrays.toString(mCorrections)
+                    + ", CorrectionUncertainties=" + Arrays.toString(mCorrectionUncertainties)
+                    + ", DeltaTheta=" + mDeltaTheta
+                    + ", DeltaPhi=" + mDeltaPhi
+                    + '}';
         }
     }
 
-    @VisibleForTesting
-    public GnssAntennaInfo(
+    private GnssAntennaInfo(
             double carrierFrequencyMHz,
-            @NonNull PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates,
-            @Nullable PhaseCenterVariationCorrections phaseCenterVariationCorrections,
-            @Nullable SignalGainCorrections signalGainCorrectionDbi) {
-        if (phaseCenterOffsetCoordinates == null) {
+            @NonNull PhaseCenterOffset phaseCenterOffset,
+            @Nullable SphericalCorrections phaseCenterVariationCorrections,
+            @Nullable SphericalCorrections signalGainCorrectionDbi) {
+        if (phaseCenterOffset == null) {
             throw new IllegalArgumentException("Phase Center Offset Coordinates cannot be null.");
         }
         mCarrierFrequencyMHz = carrierFrequencyMHz;
-        mPhaseCenterOffsetCoordinates = phaseCenterOffsetCoordinates;
+        mPhaseCenterOffset = phaseCenterOffset;
         mPhaseCenterVariationCorrections = phaseCenterVariationCorrections;
         mSignalGainCorrections = signalGainCorrectionDbi;
     }
 
+    /**
+     * Builder class for GnssAntennaInfo.
+     */
+    public static class Builder {
+        private double mCarrierFrequencyMHz;
+        private PhaseCenterOffset mPhaseCenterOffset;
+        private SphericalCorrections mPhaseCenterVariationCorrections;
+        private SphericalCorrections mSignalGainCorrections;
+
+        /**
+         * Set antenna carrier frequency (MHz).
+         * @param carrierFrequencyMHz antenna carrier frequency (MHz)
+         * @return Builder builder object
+         */
+        @NonNull
+        public Builder setCarrierFrequencyMHz(@FloatRange(from = 0.0f) double carrierFrequencyMHz) {
+            mCarrierFrequencyMHz = carrierFrequencyMHz;
+            return this;
+        }
+
+        /**
+         * Set antenna phase center offset.
+         * @param phaseCenterOffset phase center offset object
+         * @return Builder builder object
+         */
+        @NonNull
+        public Builder setPhaseCenterOffset(@NonNull PhaseCenterOffset phaseCenterOffset) {
+            mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset);
+            return this;
+        }
+
+        /**
+         * Set phase center variation corrections.
+         * @param phaseCenterVariationCorrections phase center variation corrections object
+         * @return Builder builder object
+         */
+        @NonNull
+        public Builder setPhaseCenterVariationCorrections(
+                @Nullable SphericalCorrections phaseCenterVariationCorrections) {
+            mPhaseCenterVariationCorrections = phaseCenterVariationCorrections;
+            return this;
+        }
+
+        /**
+         * Set signal gain corrections.
+         * @param signalGainCorrections signal gain corrections object
+         * @return Builder builder object
+         */
+        @NonNull
+        public Builder setSignalGainCorrections(
+                @Nullable SphericalCorrections signalGainCorrections) {
+            mSignalGainCorrections = signalGainCorrections;
+            return this;
+        }
+
+        /**
+         * Build GnssAntennaInfo object.
+         * @return instance of GnssAntennaInfo
+         */
+        @NonNull
+        public GnssAntennaInfo build() {
+            return new GnssAntennaInfo(mCarrierFrequencyMHz, mPhaseCenterOffset,
+                    mPhaseCenterVariationCorrections, mSignalGainCorrections);
+        }
+    }
+
+    @FloatRange(from = 0.0f)
     public double getCarrierFrequencyMHz() {
         return mCarrierFrequencyMHz;
     }
 
     @NonNull
-    public PhaseCenterOffsetCoordinates getPhaseCenterOffsetCoordinates() {
-        return mPhaseCenterOffsetCoordinates;
+    public PhaseCenterOffset getPhaseCenterOffset() {
+        return mPhaseCenterOffset;
     }
 
     @Nullable
-    public PhaseCenterVariationCorrections getPhaseCenterVariationCorrections() {
+    public SphericalCorrections getPhaseCenterVariationCorrections() {
         return mPhaseCenterVariationCorrections;
     }
 
     @Nullable
-    public SignalGainCorrections getSignalGainCorrections() {
+    public SphericalCorrections getSignalGainCorrections() {
         return mSignalGainCorrections;
     }
 
@@ -600,16 +422,18 @@
                                 double carrierFrequencyMHz = in.readDouble();
 
                                 ClassLoader classLoader = getClass().getClassLoader();
-                                PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates =
+                                PhaseCenterOffset phaseCenterOffset =
                                         in.readParcelable(classLoader);
-                                PhaseCenterVariationCorrections phaseCenterVariationCorrections =
+                                SphericalCorrections phaseCenterVariationCorrections =
                                         in.readParcelable(classLoader);
-                                SignalGainCorrections signalGainCorrections =
+                                SphericalCorrections signalGainCorrections =
                                         in.readParcelable(classLoader);
 
-                                return new GnssAntennaInfo(carrierFrequencyMHz,
-                                        phaseCenterOffsetCoordinates,
-                                        phaseCenterVariationCorrections, signalGainCorrections);
+                                return new GnssAntennaInfo(
+                                            carrierFrequencyMHz,
+                                            phaseCenterOffset,
+                                            phaseCenterVariationCorrections,
+                                            signalGainCorrections);
                             }
 
                             @Override
@@ -626,29 +450,18 @@
     @Override
     public void writeToParcel(@NonNull Parcel parcel, int flags) {
         parcel.writeDouble(mCarrierFrequencyMHz);
-
-        // Write Phase Center Offset
-        parcel.writeParcelable(mPhaseCenterOffsetCoordinates, flags);
-
-        // Write Phase Center Variation Corrections
+        parcel.writeParcelable(mPhaseCenterOffset, flags);
         parcel.writeParcelable(mPhaseCenterVariationCorrections, flags);
-
-        // Write Signal Gain Corrections
         parcel.writeParcelable(mSignalGainCorrections, flags);
     }
 
     @Override
     public String toString() {
-        StringBuilder builder = new StringBuilder("[ GnssAntennaInfo:\n");
-        builder.append("CarrierFrequencyMHz: " + mCarrierFrequencyMHz + "\n");
-        builder.append(mPhaseCenterOffsetCoordinates.toString());
-        builder.append(mPhaseCenterVariationCorrections == null
-                ? "PhaseCenterVariationCorrections: null\n"
-                : mPhaseCenterVariationCorrections.toString());
-        builder.append(mSignalGainCorrections == null
-                ? "SignalGainCorrections: null\n"
-                : mSignalGainCorrections.toString());
-        builder.append("]");
-        return builder.toString();
+        return "GnssAntennaInfo{"
+                + "CarrierFrequencyMHz=" + mCarrierFrequencyMHz
+                + ", PhaseCenterOffset=" + mPhaseCenterOffset
+                + ", PhaseCenterVariationCorrections=" + mPhaseCenterVariationCorrections
+                + ", SignalGainCorrections=" + mSignalGainCorrections
+                + '}';
     }
 }
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
index 930180c..5734bf2 100644
--- a/location/java/android/location/GnssCapabilities.java
+++ b/location/java/android/location/GnssCapabilities.java
@@ -16,15 +16,11 @@
 
 package android.location;
 
-import android.annotation.NonNull;
 import android.annotation.SystemApi;
 
 /**
  * A container of supported GNSS chipset capabilities.
- *
- * @hide
  */
-@SystemApi
 public final class GnssCapabilities {
     /**
      * Bit mask indicating GNSS chipset supports low power mode.
@@ -105,7 +101,10 @@
 
     /**
      * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasLowPowerMode() {
         return hasCapability(LOW_POWER_MODE);
     }
@@ -113,28 +112,40 @@
     /**
      * Returns {@code true} if GNSS chipset supports blacklisting satellites, {@code false}
      * otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasSatelliteBlacklist() {
         return hasCapability(SATELLITE_BLACKLIST);
     }
 
     /**
      * Returns {@code true} if GNSS chipset supports geofencing, {@code false} otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasGeofencing() {
         return hasCapability(GEOFENCING);
     }
 
     /**
      * Returns {@code true} if GNSS chipset supports measurements, {@code false} otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasMeasurements() {
         return hasCapability(MEASUREMENTS);
     }
 
     /**
      * Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasNavMessages() {
         return hasCapability(NAV_MESSAGES);
     }
@@ -142,7 +153,10 @@
     /**
      * Returns {@code true} if GNSS chipset supports measurement corrections, {@code false}
      * otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasMeasurementCorrections() {
         return hasCapability(MEASUREMENT_CORRECTIONS);
     }
@@ -150,7 +164,10 @@
     /**
      * Returns {@code true} if GNSS chipset supports line-of-sight satellite identification
      * measurement corrections, {@code false} otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasMeasurementCorrectionsLosSats() {
         return hasCapability(MEASUREMENT_CORRECTIONS_LOS_SATS);
     }
@@ -158,7 +175,10 @@
     /**
      * Returns {@code true} if GNSS chipset supports per satellite excess-path-length measurement
      * corrections, {@code false} otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasMeasurementCorrectionsExcessPathLength() {
         return hasCapability(MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH);
     }
@@ -166,7 +186,10 @@
     /**
      * Returns {@code true} if GNSS chipset supports reflecting planes measurement corrections,
      * {@code false} otherwise.
+     *
+     * @hide
      */
+    @SystemApi
     public boolean hasMeasurementCorrectionsReflectingPane() {
         return hasCapability(MEASUREMENT_CORRECTIONS_REFLECTING_PLANE);
     }
@@ -178,28 +201,6 @@
         return hasCapability(ANTENNA_INFO);
     }
 
-    @NonNull
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder("GnssCapabilities: ( ");
-        if (hasLowPowerMode()) sb.append("LOW_POWER_MODE ");
-        if (hasSatelliteBlacklist()) sb.append("SATELLITE_BLACKLIST ");
-        if (hasGeofencing()) sb.append("GEOFENCING ");
-        if (hasGnssAntennaInfo()) sb.append("ANTENNA_INFO ");
-        if (hasMeasurements()) sb.append("MEASUREMENTS ");
-        if (hasNavMessages()) sb.append("NAV_MESSAGES ");
-        if (hasMeasurementCorrections()) sb.append("MEASUREMENT_CORRECTIONS ");
-        if (hasMeasurementCorrectionsLosSats()) sb.append("MEASUREMENT_CORRECTIONS_LOS_SATS ");
-        if (hasMeasurementCorrectionsExcessPathLength()) {
-            sb.append("MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH ");
-        }
-        if (hasMeasurementCorrectionsReflectingPane()) {
-            sb.append("MEASUREMENT_CORRECTIONS_REFLECTING_PLANE ");
-        }
-        sb.append(")");
-        return sb.toString();
-    }
-
     private boolean hasCapability(long capability) {
         return (mGnssCapabilities & capability) == capability;
     }
diff --git a/location/java/android/location/IGnssAntennaInfoListener.aidl b/location/java/android/location/IGnssAntennaInfoListener.aidl
index 30bf5467..603ed6a 100644
--- a/location/java/android/location/IGnssAntennaInfoListener.aidl
+++ b/location/java/android/location/IGnssAntennaInfoListener.aidl
@@ -23,5 +23,4 @@
  */
 oneway interface IGnssAntennaInfoListener {
     void onGnssAntennaInfoReceived(in List<GnssAntennaInfo> gnssAntennaInfo);
-    void onStatusChanged(in int status);
 }
\ No newline at end of file
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 03e1c75..19085bf 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1813,13 +1813,7 @@
 
     /**
      * Returns the supported capabilities of the GNSS chipset.
-     *
-     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present.
-     *
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(ACCESS_FINE_LOCATION)
     public @NonNull GnssCapabilities getGnssCapabilities() {
         try {
             long gnssCapabilities = mService.getGnssCapabilities(mContext.getPackageName());
@@ -2264,35 +2258,36 @@
     }
 
     /**
-     * Registers a Gnss Antenna Info callback.
+     * Registers a Gnss Antenna Info listener. Only expect results if
+     * {@link GnssCapabilities#hasGnssAntennaInfo()} shows that antenna info is supported.
      *
-     * @param executor the executor that the callback runs on.
-     * @param callback a {@link GnssAntennaInfo.Callback} object to register.
-     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+     * @param executor the executor that the listener runs on.
+     * @param listener a {@link GnssAntennaInfo.Listener} object to register.
+     * @return {@code true} if the listener was added successfully, {@code false} otherwise.
      *
      * @throws IllegalArgumentException if executor is null
-     * @throws IllegalArgumentException if callback is null
+     * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      */
     @RequiresPermission(ACCESS_FINE_LOCATION)
-    public boolean registerAntennaInfoCallback(
+    public boolean registerAntennaInfoListener(
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull GnssAntennaInfo.Callback callback) {
+            @NonNull GnssAntennaInfo.Listener listener) {
         try {
-            return mGnssAntennaInfoListenerManager.addListener(callback, executor);
+            return mGnssAntennaInfoListenerManager.addListener(listener, executor);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Unregisters a GNSS Antenna Info callback.
+     * Unregisters a GNSS Antenna Info listener.
      *
-     * @param callback a {@link GnssAntennaInfo.Callback} object to remove.
+     * @param listener a {@link GnssAntennaInfo.Listener} object to remove.
      */
-    public void unregisterAntennaInfoCallback(@NonNull GnssAntennaInfo.Callback callback) {
+    public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) {
         try {
-            mGnssAntennaInfoListenerManager.removeListener(callback);
+            mGnssAntennaInfoListenerManager.removeListener(listener);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3043,7 +3038,7 @@
     }
 
     private class GnssAntennaInfoListenerManager extends
-            AbstractListenerManager<Void, GnssAntennaInfo.Callback> {
+            AbstractListenerManager<Void, GnssAntennaInfo.Listener> {
 
         @Nullable
         private IGnssAntennaInfoListener mListenerTransport;
@@ -3075,11 +3070,6 @@
             public void onGnssAntennaInfoReceived(final List<GnssAntennaInfo> gnssAntennaInfos) {
                 execute((callback) -> callback.onGnssAntennaInfoReceived(gnssAntennaInfos));
             }
-
-            @Override
-            public void onStatusChanged(int status) {
-                execute((listener) -> listener.onStatusChanged(status));
-            }
         }
 
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 8a5aad8..cf5a4d3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -443,20 +443,7 @@
             mStateChange.orderChanged |= repackAll();
         }
 
-        if (reason == BubbleController.DISMISS_AGED) {
-            if (DEBUG_BUBBLE_DATA) {
-                Log.d(TAG, "overflowing bubble: " + bubbleToRemove);
-            }
-            mOverflowBubbles.add(0, bubbleToRemove);
-            if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
-                // Remove oldest bubble.
-                if (DEBUG_BUBBLE_DATA) {
-                    Log.d(TAG, "Overflow full. Remove bubble: " + mOverflowBubbles.get(
-                            mOverflowBubbles.size() - 1));
-                }
-                mOverflowBubbles.remove(mOverflowBubbles.size() - 1);
-            }
-        }
+        overflowBubble(reason, bubbleToRemove);
 
         // Note: If mBubbles.isEmpty(), then mSelectedBubble is now null.
         if (Objects.equals(mSelectedBubble, bubbleToRemove)) {
@@ -468,6 +455,25 @@
         maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
     }
 
+    void overflowBubble(@DismissReason int reason, Bubble bubble) {
+        if (reason == BubbleController.DISMISS_AGED
+                || reason == BubbleController.DISMISS_USER_GESTURE) {
+            if (DEBUG_BUBBLE_DATA) {
+                Log.d(TAG, "overflowing bubble: " + bubble);
+            }
+            mOverflowBubbles.add(0, bubble);
+
+            if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
+                // Remove oldest bubble.
+                if (DEBUG_BUBBLE_DATA) {
+                    Log.d(TAG, "Overflow full. Remove bubble: " + mOverflowBubbles.get(
+                            mOverflowBubbles.size() - 1));
+                }
+                mOverflowBubbles.remove(mOverflowBubbles.size() - 1);
+            }
+        }
+    }
+
     public void dismissAll(@DismissReason int reason) {
         if (DEBUG_BUBBLE_DATA) {
             Log.d(TAG, "dismissAll: reason=" + reason);
@@ -478,9 +484,7 @@
         setExpandedInternal(false);
         setSelectedBubbleInternal(null);
         while (!mBubbles.isEmpty()) {
-            Bubble bubble = mBubbles.remove(0);
-            maybeSendDeleteIntent(reason, bubble.getEntry());
-            mStateChange.bubbleRemoved(bubble, reason);
+            doRemove(mBubbles.get(0).getKey(), reason);
         }
         dispatchPendingChanges();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index 756c598..eb836b1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -55,7 +55,6 @@
     private BubbleOverflowAdapter mAdapter;
     private RecyclerView mRecyclerView;
     private List<Bubble> mOverflowBubbles = new ArrayList<>();
-    private int mMaxBubbles;
 
     @Inject
     public BubbleOverflowActivity(BubbleController controller) {
@@ -68,7 +67,6 @@
         setContentView(R.layout.bubble_overflow_activity);
         setBackgroundColor();
 
-        mMaxBubbles = getResources().getInteger(R.integer.bubbles_max_rendered);
         mEmptyState = findViewById(R.id.bubble_overflow_empty_state);
         mRecyclerView = findViewById(R.id.bubble_overflow_recycler);
         mRecyclerView.setLayoutManager(
@@ -95,11 +93,7 @@
 
     void onDataChanged(List<Bubble> bubbles) {
         mOverflowBubbles.clear();
-        if (bubbles.size() > mMaxBubbles) {
-            mOverflowBubbles.addAll(bubbles.subList(mMaxBubbles, bubbles.size()));
-        } else {
-            mOverflowBubbles.addAll(bubbles);
-        }
+        mOverflowBubbles.addAll(bubbles);
         mAdapter.notifyDataSetChanged();
 
         if (mOverflowBubbles.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
index 7f45cc8..0329183 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
@@ -38,10 +38,10 @@
 class DistanceClassifier extends FalsingClassifier {
 
     private static final float HORIZONTAL_FLING_THRESHOLD_DISTANCE_IN = 1;
-    private static final float VERTICAL_FLING_THRESHOLD_DISTANCE_IN = 1;
+    private static final float VERTICAL_FLING_THRESHOLD_DISTANCE_IN = 1.5f;
     private static final float HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN = 3;
     private static final float VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN = 3;
-    private static final float VELOCITY_TO_DISTANCE = 80f;
+    private static final float VELOCITY_TO_DISTANCE = 30f;
     private static final float SCREEN_FRACTION_MAX_DISTANCE = 0.8f;
 
     private final float mVerticalFlingThresholdPx;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
index 957ea8d..a796f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
@@ -42,8 +42,8 @@
     // most swipes will follow somewhat of a 'C' or 'S' shape, we allow more deviance along the
     // `SECONDARY` axis.
     private static final float MAX_X_PRIMARY_DEVIANCE = .05f;
-    private static final float MAX_Y_PRIMARY_DEVIANCE = .1f;
-    private static final float MAX_X_SECONDARY_DEVIANCE = .6f;
+    private static final float MAX_Y_PRIMARY_DEVIANCE = .15f;
+    private static final float MAX_X_SECONDARY_DEVIANCE = .4f;
     private static final float MAX_Y_SECONDARY_DEVIANCE = .3f;
 
     private final float mMaxXPrimaryDeviance;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 87bdfa8..6ff1bbc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -22,7 +22,6 @@
 import android.os.UserHandle
 import android.service.controls.Control
 import android.service.controls.IControlsActionCallback
-import android.service.controls.IControlsLoadCallback
 import android.service.controls.IControlsSubscriber
 import android.service.controls.IControlsSubscription
 import android.service.controls.actions.ControlAction
@@ -63,12 +62,6 @@
     private val componentMap: MutableMap<Key, ControlsProviderLifecycleManager> =
             ArrayMap<Key, ControlsProviderLifecycleManager>()
 
-    private val loadCallbackService = object : IControlsLoadCallback.Stub() {
-        override fun accept(token: IBinder, controls: MutableList<Control>) {
-            backgroundExecutor.execute(OnLoadRunnable(token, controls))
-        }
-    }
-
     private val actionCallbackService = object : IControlsActionCallback.Stub() {
         override fun accept(
             token: IBinder,
@@ -106,7 +99,6 @@
         return ControlsProviderLifecycleManager(
                 context,
                 backgroundExecutor,
-                loadCallbackService,
                 actionCallbackService,
                 subscriberService,
                 currentUser,
@@ -130,7 +122,7 @@
         callback: ControlsBindingController.LoadCallback
     ) {
         val provider = retrieveLifecycleManager(component)
-        provider.maybeBindAndLoad(callback)
+        provider.maybeBindAndLoad(LoadSubscriber(callback))
     }
 
     override fun subscribe(controls: List<ControlInfo>) {
@@ -216,7 +208,8 @@
 
     private inner class OnLoadRunnable(
         token: IBinder,
-        val list: List<Control>
+        val list: List<Control>,
+        val callback: ControlsBindingController.LoadCallback
     ) : CallbackRunnable(token) {
         override fun run() {
             if (provider == null) {
@@ -233,9 +226,7 @@
                     return
                 }
             }
-            provider.lastLoadCallback?.accept(list) ?: run {
-                Log.w(TAG, "Null callback")
-            }
+            callback.accept(list)
             provider.unbindService()
         }
     }
@@ -277,7 +268,7 @@
     ) : CallbackRunnable(token) {
         override fun run() {
             provider?.let {
-                Log.i(TAG, "onComplete receive from '${provider.componentName}'")
+                Log.i(TAG, "onComplete receive from '${it.componentName}'")
             }
         }
     }
@@ -288,7 +279,7 @@
     ) : CallbackRunnable(token) {
         override fun run() {
             provider?.let {
-                Log.e(TAG, "onError receive from '${provider.componentName}': $error")
+                Log.e(TAG, "onError receive from '${it.componentName}': $error")
             }
         }
     }
@@ -308,6 +299,44 @@
             }
         }
     }
+
+    private inner class OnLoadErrorRunnable(
+        token: IBinder,
+        val error: String,
+        val callback: ControlsBindingController.LoadCallback
+    ) : CallbackRunnable(token) {
+        override fun run() {
+            callback.error(error)
+            provider?.let {
+                Log.e(TAG, "onError receive from '${it.componentName}': $error")
+            }
+        }
+    }
+
+    private inner class LoadSubscriber(
+        val callback: ControlsBindingController.LoadCallback
+    ) : IControlsSubscriber.Stub() {
+        val loadedControls = ArrayList<Control>()
+        var hasError = false
+
+        override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
+            backgroundExecutor.execute(OnSubscribeRunnable(token, subs))
+        }
+
+        override fun onNext(token: IBinder, c: Control) {
+            backgroundExecutor.execute { loadedControls.add(c) }
+        }
+        override fun onError(token: IBinder, s: String) {
+            hasError = true
+            backgroundExecutor.execute(OnLoadErrorRunnable(token, s, callback))
+        }
+
+        override fun onComplete(token: IBinder) {
+            if (!hasError) {
+                backgroundExecutor.execute(OnLoadRunnable(token, loadedControls, callback))
+            }
+        }
+    }
 }
 
-private data class Key(val component: ComponentName, val user: UserHandle)
\ No newline at end of file
+private data class Key(val component: ComponentName, val user: UserHandle)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
index d7f3c73..883f8a9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
@@ -135,7 +135,7 @@
     }
 
     private fun parseXml(parser: XmlPullParser): List<ControlInfo> {
-        var type = 0
+        var type: Int
         val infos = mutableListOf<ControlInfo>()
         while (parser.next().also { type = it } != XmlPullParser.END_DOCUMENT) {
             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 9ec71c7..a53fcd4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -29,7 +29,6 @@
 import android.service.controls.ControlsProviderService.CALLBACK_BUNDLE
 import android.service.controls.ControlsProviderService.CALLBACK_TOKEN
 import android.service.controls.IControlsActionCallback
-import android.service.controls.IControlsLoadCallback
 import android.service.controls.IControlsProvider
 import android.service.controls.IControlsSubscriber
 import android.service.controls.IControlsSubscription
@@ -48,8 +47,6 @@
  *
  * @property context A SystemUI context for binding to the services
  * @property executor A delayable executor for posting timeouts
- * @property loadCallbackService a callback interface to hand the remote service for loading
- *                               controls
  * @property actionCallbackService a callback interface to hand the remote service for sending
  *                                 action responses
  * @property subscriberService an "subscriber" interface for requesting and accepting updates for
@@ -60,15 +57,12 @@
 class ControlsProviderLifecycleManager(
     private val context: Context,
     private val executor: DelayableExecutor,
-    private val loadCallbackService: IControlsLoadCallback.Stub,
     private val actionCallbackService: IControlsActionCallback.Stub,
     private val subscriberService: IControlsSubscriber.Stub,
     val user: UserHandle,
     val componentName: ComponentName
 ) : IBinder.DeathRecipient {
 
-    var lastLoadCallback: ControlsBindingController.LoadCallback? = null
-        private set
     val token: IBinder = Binder()
     @GuardedBy("subscriptions")
     private val subscriptions = mutableListOf<IControlsSubscription>()
@@ -156,9 +150,12 @@
             bindService(false)
             return
         }
-        if (Message.Load in queue) {
-            load()
+
+        queue.filter { it is Message.Load }.forEach {
+            val msg = it as Message.Load
+            load(msg.subscriber)
         }
+
         queue.filter { it is Message.Subscribe }.flatMap { (it as Message.Subscribe).list }.run {
             if (this.isNotEmpty()) {
                 subscribe(this)
@@ -193,12 +190,12 @@
         }
     }
 
-    private fun load() {
+    private fun load(subscriber: IControlsSubscriber.Stub) {
         if (DEBUG) {
             Log.d(TAG, "load $componentName")
         }
-        if (!(wrapper?.load(loadCallbackService) ?: false)) {
-            queueMessage(Message.Load)
+        if (!(wrapper?.load(subscriber) ?: false)) {
+            queueMessage(Message.Load(subscriber))
             binderDied()
         }
     }
@@ -213,27 +210,23 @@
     }
 
     /**
-     * Request a call to [ControlsProviderService.loadAvailableControls].
+     * Request a call to [IControlsProvider.load].
      *
      * If the service is not bound, the call will be queued and the service will be bound first.
-     * The service will be bound after the controls are returned or the call times out.
+     * The service will be unbound after the controls are returned or the call times out.
      *
-     * @param callback a callback in which to return the result back. If the call times out
-     *                 [ControlsBindingController.LoadCallback.error] will be called instead.
+     * @param subscriber the subscriber that manages coordination for loading controls
      */
-    fun maybeBindAndLoad(callback: ControlsBindingController.LoadCallback) {
+    fun maybeBindAndLoad(subscriber: IControlsSubscriber.Stub) {
         unqueueMessage(Message.Unbind)
-        lastLoadCallback = callback
         onLoadCanceller = executor.executeDelayed({
             // Didn't receive a response in time, log and send back error
             Log.d(TAG, "Timeout waiting onLoad for $componentName")
-            callback.error("Timeout waiting onLoad")
-            // Don't accept load callbacks after this
-            lastLoadCallback = null
+            subscriber.onError(token, "Timeout waiting onLoad")
             unbindService()
         }, LOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS)
 
-        invokeOrQueue(::load, Message.Load)
+        invokeOrQueue({ load(subscriber) }, Message.Load(subscriber))
     }
 
     /**
@@ -324,7 +317,6 @@
      * Request unbind from the service.
      */
     fun unbindService() {
-        lastLoadCallback = null
         onLoadCanceller?.run()
         onLoadCanceller = null
 
@@ -344,7 +336,7 @@
      */
     sealed class Message {
         abstract val type: Int
-        object Load : Message() {
+        class Load(val subscriber: IControlsSubscriber.Stub) : Message() {
             override val type = MSG_LOAD
         }
         object Unbind : Message() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
index b90f892..b2afd3c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
@@ -18,7 +18,6 @@
 
 import android.service.controls.actions.ControlAction
 import android.service.controls.IControlsActionCallback
-import android.service.controls.IControlsLoadCallback
 import android.service.controls.IControlsProvider
 import android.service.controls.IControlsSubscriber
 import android.service.controls.IControlsSubscription
@@ -45,9 +44,9 @@
         }
     }
 
-    fun load(cb: IControlsLoadCallback): Boolean {
+    fun load(subscriber: IControlsSubscriber): Boolean {
         return callThroughService {
-            service.load(cb)
+            service.load(subscriber)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
index 89caace..ac5e089 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
@@ -58,13 +58,13 @@
     private var listOfServices = emptyList<CandidateInfo>()
 
     private val callback = object : ControlsListingController.ControlsListingCallback {
-        override fun onServicesUpdated(list: List<CandidateInfo>) {
+        override fun onServicesUpdated(candidates: List<CandidateInfo>) {
             backgroundExecutor.execute {
-                val collator = Collator.getInstance(resources.getConfiguration().locale)
+                val collator = Collator.getInstance(resources.configuration.locales[0])
                 val localeComparator = compareBy<CandidateInfo, CharSequence>(collator) {
                     it.loadLabel()
                 }
-                listOfServices = list.sortedWith(localeComparator)
+                listOfServices = candidates.sortedWith(localeComparator)
                 uiExecutor.execute(::notifyDataSetChanged)
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 9952b97..af4a977 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -70,7 +70,7 @@
             target: RecyclerView.ViewHolder
         ): Boolean {
             return currentModel?.onMoveItem(
-                    viewHolder.adapterPosition, target.adapterPosition) != null
+                    viewHolder.layoutPosition, target.layoutPosition) != null
         }
 
         override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
index d893caa..8e47f64 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
@@ -45,6 +45,6 @@
 
     @FunctionalInterface
     interface ControlsListingCallback {
-        fun onServicesUpdated(list: List<CandidateInfo>)
+        fun onServicesUpdated(candidates: List<CandidateInfo>)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 98cdf28..f4fd375 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -130,8 +130,7 @@
     private val listingCallback = object : ControlsListingController.ControlsListingCallback {
         override fun onServicesUpdated(candidates: List<CandidateInfo>) {
             bgExecutor.execute {
-                val collator = Collator.getInstance(context.getResources()
-                        .getConfiguration().locale)
+                val collator = Collator.getInstance(context.resources.configuration.locales[0])
                 val localeComparator = compareBy<CandidateInfo, CharSequence>(collator) {
                     it.loadLabel()
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 071198b..d3d4287 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -42,7 +42,7 @@
     val intent: PendingIntent
 ) : Dialog(parentContext) {
 
-    lateinit var activityView: ActivityView
+    var activityView: ActivityView
 
     val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() {
         override fun onActivityViewReady(view: ActivityView) {
@@ -61,24 +61,28 @@
         override fun onTaskRemovalStarted(taskId: Int) {}
     }
 
-    init {
-        val window = getWindow()
-        window.requestFeature(Window.FEATURE_NO_TITLE)
+    @Suppress("DEPRECATION")
+    private fun Window.setWindowParams() {
+        requestFeature(Window.FEATURE_NO_TITLE)
 
         // Inflate the decor view, so the attributes below are not overwritten by the theme.
-        window.getDecorView()
-        window.getAttributes().systemUiVisibility =
-            (window.getAttributes().systemUiVisibility
-                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
+        decorView
+        attributes.systemUiVisibility =
+                (attributes.systemUiVisibility
+                        or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                        or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
 
-        window.setLayout(MATCH_PARENT, MATCH_PARENT)
-        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
-        window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-            or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-            or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
-        window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
-        window.getAttributes().setFitInsetsTypes(0 /* types */)
+        setLayout(MATCH_PARENT, MATCH_PARENT)
+        clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+        addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
+        setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+        getAttributes().setFitInsetsTypes(0 /* types */)
+    }
+
+    init {
+        getWindow()?.setWindowParams()
 
         setContentView(R.layout.controls_detail_dialog)
 
@@ -89,9 +93,9 @@
     }
 
     override fun show() {
-        val attrs = getWindow().getAttributes()
-        attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
-        getWindow().setAttributes(attrs)
+        val attrs = getWindow()?.attributes
+        attrs?.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+        getWindow()?.attributes = attrs
 
         activityView.setCallback(stateCallback)
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 45d7397..cca56c2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -60,7 +60,7 @@
 
         val gestureListener = ToggleRangeGestureListener(cvh.layout)
         val gestureDetector = GestureDetector(context, gestureListener)
-        cvh.layout.setOnTouchListener({ v: View, e: MotionEvent ->
+        cvh.layout.setOnTouchListener { _: View, e: MotionEvent ->
             if (gestureDetector.onTouchEvent(e)) {
                 return@setOnTouchListener true
             }
@@ -72,7 +72,7 @@
             }
 
             return@setOnTouchListener false
-        })
+        }
     }
 
     override fun bind(cws: ControlWithState) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b1db7df..374153c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -80,7 +80,8 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.Dependency;
+import com.android.systemui.DumpController;
+import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIFactory;
@@ -144,7 +145,7 @@
  * directly to the keyguard UI is posted to a {@link android.os.Handler} to ensure it is taken on the UI
  * thread of the keyguard.
  */
-public class KeyguardViewMediator extends SystemUI {
+public class KeyguardViewMediator extends SystemUI implements Dumpable {
     private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
     private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
 
@@ -222,10 +223,10 @@
     private final FalsingManager mFalsingManager;
 
     /** High level access to the power manager for WakeLocks */
-    private PowerManager mPM;
+    private final PowerManager mPM;
 
     /** TrustManager for letting it know when we change visibility */
-    private TrustManager mTrustManager;
+    private final TrustManager mTrustManager;
 
     /**
      * Used to keep the device awake while to ensure the keyguard finishes opening before
@@ -283,7 +284,7 @@
 
     // the properties of the keyguard
 
-    private KeyguardUpdateMonitor mUpdateMonitor;
+    private final KeyguardUpdateMonitor mUpdateMonitor;
 
     /**
      * Last SIM state reported by the telephony system.
@@ -610,6 +611,7 @@
         @Override
         public void keyguardGone() {
             Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardGone");
+            mNotificationShadeWindowController.setKeyguardGoingAway(false);
             mKeyguardDisplayManager.hide();
             Trace.endSection();
         }
@@ -696,7 +698,9 @@
             NotificationShadeWindowController notificationShadeWindowController,
             Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManagerLazy,
             DismissCallbackRegistry dismissCallbackRegistry,
-            @UiBackground Executor uiBgExecutor) {
+            KeyguardUpdateMonitor keyguardUpdateMonitor, DumpController dumpController,
+            @UiBackground Executor uiBgExecutor, PowerManager powerManager,
+            TrustManager trustManager) {
         super(context);
         mFalsingManager = falsingManager;
         mLockPatternUtils = lockPatternUtils;
@@ -705,6 +709,10 @@
         mStatusBarKeyguardViewManagerLazy = statusBarKeyguardViewManagerLazy;
         mDismissCallbackRegistry = dismissCallbackRegistry;
         mUiBgExecutor = uiBgExecutor;
+        mUpdateMonitor = keyguardUpdateMonitor;
+        mPM = powerManager;
+        mTrustManager = trustManager;
+        dumpController.registerDumpable(this);
         mShowHomeOverLockscreen = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
@@ -731,9 +739,6 @@
     }
 
     private void setupLocked() {
-        mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mTrustManager = mContext.getSystemService(TrustManager.class);
-
         mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
         mShowKeyguardWakeLock.setReferenceCounted(false);
 
@@ -754,8 +759,6 @@
 
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
-        mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
-
         KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());
 
         // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 2c023ca..2ba0315 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -16,9 +16,13 @@
 
 package com.android.systemui.keyguard.dagger;
 
+import android.app.trust.TrustManager;
 import android.content.Context;
+import android.os.PowerManager;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.DumpController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -54,6 +58,10 @@
             NotificationShadeWindowController notificationShadeWindowController,
             Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManagerLazy,
             DismissCallbackRegistry dismissCallbackRegistry,
+            KeyguardUpdateMonitor updateMonitor,
+            DumpController dumpController,
+            PowerManager powerManager,
+            TrustManager trustManager,
             @UiBackground Executor uiBgExecutor) {
         return new KeyguardViewMediator(
                 context,
@@ -63,6 +71,10 @@
                 notificationShadeWindowController,
                 statusBarKeyguardViewManagerLazy,
                 dismissCallbackRegistry,
-                uiBgExecutor);
+                updateMonitor,
+                dumpController,
+                uiBgExecutor,
+                powerManager,
+                trustManager);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
index aaf4849..711d6a6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
@@ -19,7 +19,6 @@
 import android.content.Context
 import android.graphics.Bitmap
 import android.graphics.Canvas
-import android.graphics.Point
 import android.graphics.Rect
 import android.renderscript.Allocation
 import android.renderscript.Element
@@ -27,9 +26,11 @@
 import android.renderscript.ScriptIntrinsicBlur
 import android.util.Log
 import android.util.MathUtils
+import android.util.Size
+import android.view.WindowManager
+import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.graphics.ColorUtils
 import com.android.systemui.statusbar.notification.MediaNotificationProcessor
-
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -41,10 +42,9 @@
 @Singleton
 class MediaArtworkProcessor @Inject constructor() {
 
-    private val mTmpSize = Point()
     private var mArtworkCache: Bitmap? = null
 
-    fun processArtwork(context: Context, artwork: Bitmap): Bitmap? {
+    fun processArtwork(context: Context, artwork: Bitmap, windowType: Int): Bitmap? {
         if (mArtworkCache != null) {
             return mArtworkCache
         }
@@ -54,9 +54,9 @@
         var output: Allocation? = null
         var inBitmap: Bitmap? = null
         try {
-            context.display.getSize(mTmpSize)
+            val size = getWindowSize(context, windowType)
             val rect = Rect(0, 0, artwork.width, artwork.height)
-            MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE))
+            MathUtils.fitRect(rect, Math.max(size.width / DOWNSAMPLE, size.height / DOWNSAMPLE))
             inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(),
                     true /* filter */)
             // Render script blurs only support ARGB_8888, we need a conversion if we got a
@@ -98,4 +98,15 @@
         mArtworkCache?.recycle()
         mArtworkCache = null
     }
+
+    @VisibleForTesting
+    internal fun getWindowSize(context: Context, windowType: Int): Size {
+        val windowContext = context.display?.let {
+            context.createDisplayContext(it)
+                    .createWindowContext(windowType, null)
+        } ?: run { throw NullPointerException("Display is null") }
+        val windowManager = windowContext.getSystemService(WindowManager::class.java)
+                ?: run { throw NullPointerException("Null window manager") }
+        return windowManager.currentWindowMetrics.size
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index d0af106..f8db922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.statusbar;
 
-import static com.android.systemui.Dependency.MAIN_HANDLER;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK;
 import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER;
@@ -36,7 +35,6 @@
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.AsyncTask;
-import android.os.Handler;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
@@ -44,6 +42,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.ImageView;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -52,6 +51,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.Interpolators;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.dagger.StatusBarModule;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
@@ -73,6 +73,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 import dagger.Lazy;
 
@@ -110,7 +111,7 @@
     @Nullable
     private LockscreenWallpaper mLockscreenWallpaper;
 
-    private final Handler mHandler = Dependency.get(MAIN_HANDLER);
+    private final Executor mMainExecutor;
 
     private final Context mContext;
     private final MediaSessionManager mMediaSessionManager;
@@ -181,7 +182,8 @@
             Lazy<NotificationShadeWindowController> notificationShadeWindowController,
             NotificationEntryManager notificationEntryManager,
             MediaArtworkProcessor mediaArtworkProcessor,
-            KeyguardBypassController keyguardBypassController) {
+            KeyguardBypassController keyguardBypassController,
+            @Main Executor mainExecutor) {
         mContext = context;
         mMediaArtworkProcessor = mediaArtworkProcessor;
         mKeyguardBypassController = keyguardBypassController;
@@ -194,6 +196,7 @@
         mStatusBarLazy = statusBarLazy;
         mNotificationShadeWindowController = notificationShadeWindowController;
         mEntryManager = notificationEntryManager;
+        mMainExecutor = mainExecutor;
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onPendingEntryAdded(NotificationEntry entry) {
@@ -623,7 +626,7 @@
                                 mBackdrop.setVisibility(View.GONE);
                                 mBackdropFront.animate().cancel();
                                 mBackdropBack.setImageDrawable(null);
-                                mHandler.post(mHideBackdropFront);
+                                mMainExecutor.execute(mHideBackdropFront);
                             });
                     if (mKeyguardStateController.isKeyguardFadingAway()) {
                         mBackdrop.animate()
@@ -668,7 +671,8 @@
     };
 
     private Bitmap processArtwork(Bitmap artwork) {
-        return mMediaArtworkProcessor.processArtwork(mContext, artwork);
+        return mMediaArtworkProcessor.processArtwork(mContext, artwork,
+                WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE);
     }
 
     @MainThread
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 0b37c22..cd5bb77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -43,6 +43,8 @@
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.tracing.ProtoTracer;
 
+import java.util.concurrent.Executor;
+
 import javax.inject.Singleton;
 
 import dagger.Lazy;
@@ -88,14 +90,16 @@
             Lazy<NotificationShadeWindowController> notificationShadeWindowController,
             NotificationEntryManager notificationEntryManager,
             MediaArtworkProcessor mediaArtworkProcessor,
-            KeyguardBypassController keyguardBypassController) {
+            KeyguardBypassController keyguardBypassController,
+            @Main Executor mainExecutor) {
         return new NotificationMediaManager(
                 context,
                 statusBarLazy,
                 notificationShadeWindowController,
                 notificationEntryManager,
                 mediaArtworkProcessor,
-                keyguardBypassController);
+                keyguardBypassController,
+                mainExecutor);
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 234ab93..5008133 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -482,6 +482,7 @@
      * once per notification as the packageInfo can't technically change for a notification row.
      */
     private void cacheIsSystemNotification() {
+        //TODO: This probably shouldn't be in ExpandableNotificationRow
         if (mEntry != null && mEntry.mIsSystemNotification == null) {
             if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
                 // Run async task once, only if it hasn't already been executed. Note this is
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index d016217..2dd42c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -40,6 +40,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
+import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -101,7 +102,8 @@
             IActivityManager activityManager, DozeParameters dozeParameters,
             StatusBarStateController statusBarStateController,
             ConfigurationController configurationController,
-            KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor) {
+            KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor,
+            DumpController dumpController) {
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
@@ -111,6 +113,7 @@
         mLpChanged = new LayoutParams();
         mKeyguardBypassController = keyguardBypassController;
         mColorExtractor = colorExtractor;
+        dumpController.registerDumpable(this);
 
         mLockScreenDisplayTimeout = context.getResources()
                 .getInteger(R.integer.config_lockScreenDisplayTimeout);
@@ -594,7 +597,7 @@
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("StatusBarWindowController:");
+        pw.println(TAG + ":");
         pw.println("  mKeyguardDisplayMode=" + mKeyguardDisplayMode);
         pw.println(mCurrentState);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
index 0487ce6..ca4b67d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
@@ -132,7 +132,6 @@
      *
      * @param content The content that has moved.
      */
-    @JvmOverloads
     fun onContentMoved(content: FloatingContent) {
 
         // Ignore calls when we are currently resolving conflicts, since those calls are from
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index daea7a7..5e4f971 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -203,7 +203,8 @@
         // Bubbles get added to status bar window view
         mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
                 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController, mColorExtractor);
+                mConfigurationController, mKeyguardBypassController, mColorExtractor,
+                mDumpController);
         mNotificationShadeWindowController.setNotificationShadeView(
                 mSuperStatusBarViewFactory.getNotificationShadeWindowView());
         mNotificationShadeWindowController.attach();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index b412ca5..6677b80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -197,7 +197,8 @@
         // Bubbles get added to status bar window view
         mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
                 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController, mColorExtractor);
+                mConfigurationController, mKeyguardBypassController, mColorExtractor,
+                mDumpController);
         mNotificationShadeWindowController.setNotificationShadeView(
                 mSuperStatusBarViewFactory.getNotificationShadeWindowView());
         mNotificationShadeWindowController.attach();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
index 44454d9..e5ab9be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
@@ -60,10 +60,10 @@
         mClassifier.onTouchEvent(appendDownEvent(1, 1));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        mClassifier.onTouchEvent(appendMoveEvent(1, 2));
+        mClassifier.onTouchEvent(appendMoveEvent(1, 40));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        mClassifier.onTouchEvent(appendUpEvent(1, 40));
+        mClassifier.onTouchEvent(appendUpEvent(1, 80));
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index 40075c8..02bfc19e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -45,7 +45,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
-class ControlsBindingControllerTest : SysuiTestCase() {
+class ControlsBindingControllerImplTest : SysuiTestCase() {
 
     companion object {
         fun <T> any(): T = Mockito.any<T>()
@@ -95,7 +95,7 @@
 
         assertEquals(1, providers.size)
         val provider = providers.first()
-        verify(provider).maybeBindAndLoad(callback)
+        verify(provider).maybeBindAndLoad(any())
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index ddd6b12..a3e59e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -19,7 +19,6 @@
 import android.content.ComponentName
 import android.os.UserHandle
 import android.service.controls.IControlsActionCallback
-import android.service.controls.IControlsLoadCallback
 import android.service.controls.IControlsProvider
 import android.service.controls.IControlsSubscriber
 import android.service.controls.actions.ControlAction
@@ -32,13 +31,13 @@
 import org.junit.After
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.anyString
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Captor
@@ -54,8 +53,6 @@
     @Mock
     private lateinit var actionCallbackService: IControlsActionCallback.Stub
     @Mock
-    private lateinit var loadCallbackService: IControlsLoadCallback.Stub
-    @Mock
     private lateinit var subscriberService: IControlsSubscriber.Stub
     @Mock
     private lateinit var service: IControlsProvider.Stub
@@ -85,7 +82,6 @@
         manager = ControlsProviderLifecycleManager(
                 context,
                 executor,
-                loadCallbackService,
                 actionCallbackService,
                 subscriberService,
                 UserHandle.of(0),
@@ -113,31 +109,29 @@
 
     @Test
     fun testMaybeBindAndLoad() {
-        manager.maybeBindAndLoad(loadCallback)
+        manager.maybeBindAndLoad(subscriberService)
 
-        verify(service).load(loadCallbackService)
+        verify(service).load(subscriberService)
 
         assertTrue(mContext.isBound(componentName))
-        assertEquals(loadCallback, manager.lastLoadCallback)
     }
 
     @Test
     fun testMaybeUnbind_bindingAndCallback() {
-        manager.maybeBindAndLoad(loadCallback)
+        manager.maybeBindAndLoad(subscriberService)
 
         manager.unbindService()
         assertFalse(mContext.isBound(componentName))
-        assertNull(manager.lastLoadCallback)
     }
 
     @Test
     fun testMaybeBindAndLoad_timeout() {
-        manager.maybeBindAndLoad(loadCallback)
+        manager.maybeBindAndLoad(subscriberService)
 
         executor.advanceClockToLast()
         executor.runAllReady()
 
-        verify(loadCallback).error(anyString())
+        verify(subscriberService).onError(any(), anyString())
     }
 
     @Test
@@ -160,4 +154,4 @@
                 eq(actionCallbackService))
         assertEquals(action, wrapperCaptor.getValue().getWrappedAction())
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
index 9e7ce06..cd82844 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
@@ -18,7 +18,6 @@
 
 import android.os.RemoteException
 import android.service.controls.IControlsActionCallback
-import android.service.controls.IControlsLoadCallback
 import android.service.controls.IControlsProvider
 import android.service.controls.IControlsSubscriber
 import android.service.controls.IControlsSubscription
@@ -56,9 +55,6 @@
     private lateinit var subscriber: IControlsSubscriber
 
     @Mock
-    private lateinit var loadCallback: IControlsLoadCallback
-
-    @Mock
     private lateinit var actionCallback: IControlsActionCallback
 
     @Captor
@@ -81,16 +77,16 @@
 
     @Test
     fun testLoad_happyPath() {
-        val result = wrapper.load(loadCallback)
+        val result = wrapper.load(subscriber)
 
         assertTrue(result)
-        verify(service).load(loadCallback)
+        verify(service).load(subscriber)
     }
 
     @Test
     fun testLoad_error() {
         `when`(service.load(any())).thenThrow(exception)
-        val result = wrapper.load(loadCallback)
+        val result = wrapper.load(subscriber)
 
         assertFalse(result)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index acc30d9..9a707caa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -18,24 +18,30 @@
 
 import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -60,6 +66,9 @@
     private @Mock NotificationShadeWindowController mNotificationShadeWindowController;
     private @Mock BroadcastDispatcher mBroadcastDispatcher;
     private @Mock DismissCallbackRegistry mDismissCallbackRegistry;
+    private @Mock DumpController mDumpController;
+    private @Mock PowerManager mPowerManager;
+    private @Mock TrustManager mTrustManager;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
     private FalsingManagerFake mFalsingManager;
@@ -69,24 +78,33 @@
         MockitoAnnotations.initMocks(this);
         mFalsingManager = new FalsingManagerFake();
 
-        mDependency.injectTestDependency(FalsingManager.class, mFalsingManager);
-        mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mUpdateMonitor);
-
         when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
+        when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
 
-        TestableLooper.get(this).runWithLooper(() -> {
-            mViewMediator = new KeyguardViewMediator(
-                    mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
-                    mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager,
-                    mDismissCallbackRegistry, mUiBgExecutor);
-        });
+        mViewMediator = new KeyguardViewMediator(
+                mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
+                mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager,
+                mDismissCallbackRegistry, mUpdateMonitor, mDumpController, mUiBgExecutor,
+                mPowerManager, mTrustManager);
+        mViewMediator.start();
     }
 
     @Test
     public void testOnGoingToSleep_UpdatesKeyguardGoingAway() {
-        mViewMediator.start();
         mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
         verify(mUpdateMonitor).setKeyguardGoingAway(false);
         verify(mNotificationShadeWindowController, never()).setKeyguardGoingAway(anyBoolean());
     }
+
+    @Test
+    public void testRegisterDumpable() {
+        verify(mDumpController).registerDumpable(eq(mViewMediator));
+        verify(mNotificationShadeWindowController, never()).setKeyguardGoingAway(anyBoolean());
+    }
+
+    @Test
+    public void testKeyguardGone_notGoingaway() {
+        mViewMediator.mViewMediatorCallback.keyguardGone();
+        verify(mNotificationShadeWindowController).setKeyguardGoingAway(eq(false));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
index 72e6df2..a27c085 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
@@ -16,15 +16,14 @@
 
 package com.android.systemui.statusbar
 
-import com.google.common.truth.Truth.assertThat
-
 import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.Color
-import android.graphics.Point
 import android.testing.AndroidTestingRunner
+import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -32,6 +31,7 @@
 
 private const val WIDTH = 200
 private const val HEIGHT = 200
+private const val WINDOW_TYPE = TYPE_NOTIFICATION_SHADE
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
@@ -46,10 +46,10 @@
     fun setUp() {
         processor = MediaArtworkProcessor()
 
-        val point = Point()
-        context.display.getSize(point)
-        screenWidth = point.x
-        screenHeight = point.y
+        val size = processor.getWindowSize(context, WINDOW_TYPE)
+
+        screenWidth = size.width
+        screenHeight = size.height
     }
 
     @After
@@ -63,7 +63,7 @@
         val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)
         Canvas(artwork).drawColor(Color.BLUE)
         // WHEN the background is created from the artwork
-        val background = processor.processArtwork(context, artwork)!!
+        val background = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
         // THEN the background has the size of the screen that has been downsamples
         assertThat(background.height).isLessThan(screenHeight)
         assertThat(background.width).isLessThan(screenWidth)
@@ -76,8 +76,8 @@
         val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)
         Canvas(artwork).drawColor(Color.BLUE)
         // WHEN the background is processed twice
-        val background1 = processor.processArtwork(context, artwork)!!
-        val background2 = processor.processArtwork(context, artwork)!!
+        val background1 = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
+        val background2 = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
         // THEN the two bitmaps are the same
         // Note: This is currently broken and trying to use caching causes issues
         assertThat(background1).isNotSameAs(background2)
@@ -89,7 +89,7 @@
         val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ALPHA_8)
         Canvas(artwork).drawColor(Color.BLUE)
         // WHEN the background is created from the artwork
-        val background = processor.processArtwork(context, artwork)!!
+        val background = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
         // THEN the background has Config ARGB_8888
         assertThat(background.config).isEqualTo(Bitmap.Config.ARGB_8888)
     }
@@ -102,7 +102,7 @@
         // AND the artwork is recycled
         artwork.recycle()
         // WHEN the background is created from the artwork
-        val background = processor.processArtwork(context, artwork)
+        val background = processor.processArtwork(context, artwork, WINDOW_TYPE)
         // THEN the processed bitmap is null
         assertThat(background).isNull()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 6a6e5c8..98f12ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -52,73 +52,55 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArraySet;
-import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.NotificationVisibility;
-import com.android.internal.util.NotificationMessagingUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
-import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.row.RowContentBindParams;
-import com.android.systemui.statusbar.notification.row.RowContentBindStage;
+import com.android.systemui.statusbar.notification.row.NotificationEntryManagerInflationTest;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
-import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.leak.LeakDetector;
-import com.android.systemui.util.time.FakeSystemClock;
 
-import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
+/**
+ * Unit tests for {@link NotificationEntryManager}. This test will not test any interactions with
+ * inflation. Instead, for functional inflation tests, see
+ * {@link NotificationEntryManagerInflationTest}.
+ */
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper()
@@ -129,17 +111,11 @@
     @Mock private NotificationPresenter mPresenter;
     @Mock private KeyguardEnvironment mEnvironment;
     @Mock private ExpandableNotificationRow mRow;
-    @Mock private NotificationListContainer mListContainer;
     @Mock private NotificationEntryListener mEntryListener;
     @Mock private NotificationRemoveInterceptor mRemoveInterceptor;
-    @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
     @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private RankingMap mRankingMap;
-    @Mock private RemoteInputController mRemoteInputController;
-    @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
-    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private NotificationGroupManager mGroupManager;
-    @Mock private NotificationGutsManager mGutsManager;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private RowInflaterTask mAsyncInflationTask;
@@ -147,18 +123,12 @@
     @Mock private FeatureFlags mFeatureFlags;
     @Mock private LeakDetector mLeakDetector;
     @Mock private NotificationMediaManager mNotificationMediaManager;
-    @Mock private ExpandableNotificationRowComponent.Builder
-            mExpandableNotificationRowComponentBuilder;
-    @Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent;
-    @Mock private FalsingManager mFalsingManager;
-    @Mock private KeyguardBypassController mKeyguardBypassController;
-    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private NotificationRowBinder mNotificationRowBinder;
 
     private int mId;
     private NotificationEntry mEntry;
     private StatusBarNotification mSbn;
-    private TestableNotificationEntryManager mEntryManager;
-    private CountDownLatch mCountDownLatch;
+    private NotificationEntryManager mEntryManager;
 
     private void setUserSentiment(String key, int sentiment) {
         doAnswer(invocationOnMock -> {
@@ -202,41 +172,16 @@
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(SmartReplyController.class);
 
-        mCountDownLatch = new CountDownLatch(1);
-
         allowTestableLooperAsMainThread();
         mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
                 Handler.createAsync(TestableLooper.get(this).getLooper()));
-        when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-        when(mListContainer.getViewParentForNotification(any())).thenReturn(
-                new FrameLayout(mContext));
 
         mEntry = createNotification();
         mSbn = mEntry.getSbn();
 
-        mEntry.expandedIcon = mock(StatusBarIconView.class);
-
-        RowContentBindStage bindStage = mock(RowContentBindStage.class);
-        when(bindStage.getStageParams(any())).thenReturn(new RowContentBindParams());
-        NotificationRowBinderImpl notificationRowBinder =
-                new NotificationRowBinderImpl(mContext,
-                        new NotificationMessagingUtil(mContext),
-                        mRemoteInputManager,
-                        mLockscreenUserManager,
-                        mock(NotifBindPipeline.class),
-                        bindStage,
-                        true, /* allowLongPress */
-                        mKeyguardBypassController,
-                        mStatusBarStateController,
-                        mGroupManager,
-                        mGutsManager,
-                        mNotificationInterruptionStateProvider,
-                        RowInflaterTask::new,
-                        mExpandableNotificationRowComponentBuilder);
-
         when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
         when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
-        mEntryManager = new TestableNotificationEntryManager(
+        mEntryManager = new NotificationEntryManager(
                 mLogger,
                 mGroupManager,
                 new NotificationRankingManager(
@@ -250,7 +195,7 @@
                         mock(HighPriorityProvider.class)),
                 mEnvironment,
                 mFeatureFlags,
-                () -> notificationRowBinder,
+                () -> mNotificationRowBinder,
                 () -> mRemoteInputManager,
                 mLeakDetector,
                 mock(ForegroundServiceDismissalFeatureController.class)
@@ -259,152 +204,45 @@
         mEntryManager.addNotificationEntryListener(mEntryListener);
         mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor);
 
-        notificationRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback);
-        notificationRowBinder.setInflationCallback(mEntryManager);
-        notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
-
-        setUserSentiment(
-                mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
-
-        ArgumentCaptor<ExpandableNotificationRow> viewCaptor =
-                ArgumentCaptor.forClass(ExpandableNotificationRow.class);
-        when(mExpandableNotificationRowComponentBuilder
-                .expandableNotificationRow(viewCaptor.capture()))
-                .thenReturn(mExpandableNotificationRowComponentBuilder);
-        when(mExpandableNotificationRowComponentBuilder
-                .notificationEntry(any()))
-                .thenReturn(mExpandableNotificationRowComponentBuilder);
-        when(mExpandableNotificationRowComponentBuilder
-                .onDismissRunnable(any()))
-                .thenReturn(mExpandableNotificationRowComponentBuilder);
-        when(mExpandableNotificationRowComponentBuilder
-                .inflationCallback(any()))
-                .thenReturn(mExpandableNotificationRowComponentBuilder);
-        when(mExpandableNotificationRowComponentBuilder
-                .rowContentBindStage(any()))
-                .thenReturn(mExpandableNotificationRowComponentBuilder);
-        when(mExpandableNotificationRowComponentBuilder
-                .onExpandClickListener(any()))
-                .thenReturn(mExpandableNotificationRowComponentBuilder);
-
-        when(mExpandableNotificationRowComponentBuilder.build())
-                .thenReturn(mExpandableNotificationRowComponent);
-        when(mExpandableNotificationRowComponent.getExpandableNotificationRowController())
-                .thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
-                        new ExpandableNotificationRowController(
-                                viewCaptor.getValue(),
-                                mock(ActivatableNotificationViewController.class),
-                                mNotificationMediaManager,
-                                mock(PluginManager.class),
-                                new FakeSystemClock(),
-                                "FOOBAR", "FOOBAR",
-                                mKeyguardBypassController,
-                                mGroupManager,
-                                bindStage,
-                                mock(NotificationLogger.class),
-                                mHeadsUpManager,
-                                mPresenter,
-                                mStatusBarStateController,
-                                mEntryManager,
-                                mGutsManager,
-                                true,
-                                null,
-                                mFalsingManager
-                        ));
+        setUserSentiment(mSbn.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
     }
 
-    @After
-    public void tearDown() {
-        // CLEAN UP inflation tasks so they don't callback in a future test
-        mEntry.abortTask();
-    }
-
-    // TODO: These tests are closer to functional tests and we should move them to their own file.
-    // and also strip some of the verifies that make the test too complex
     @Test
-    @Ignore
-    public void testAddNotification() throws Exception {
-        TestableLooper.get(this).processAllMessages();
-
-        doAnswer(invocation -> {
-            mCountDownLatch.countDown();
-            return null;
-        }).when(mBindCallback).onBindRow(any(), any(), any(), any());
-
-        // Post on main thread, otherwise we will be stuck waiting here for the inflation finished
-        // callback forever, since it won't execute until the tests ends.
+    public void testAddNotification_setsUserSentiment() {
         mEntryManager.addNotification(mSbn, mRankingMap);
-        TestableLooper.get(this).processMessages(1);
-        assertTrue(mCountDownLatch.await(10, TimeUnit.SECONDS));
-        assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS));
 
-        // Check that no inflation error occurred.
-        verify(mEntryListener, never()).onInflationError(any(), any());
-
-        // Row inflation:
         ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass(
                 NotificationEntry.class);
-        verify(mBindCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any());
+        verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
         NotificationEntry entry = entryCaptor.getValue();
-        verify(mRemoteInputManager).bindRow(entry.getRow());
 
-        // Row content inflation:
-        verify(mEntryListener).onNotificationAdded(entry);
-        verify(mPresenter).updateNotificationViews();
-
-        assertEquals(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()), entry);
-        assertNotNull(entry.getRow());
-        assertEquals(mEntry.getUserSentiment(),
-                Ranking.USER_SENTIMENT_NEUTRAL);
+        assertEquals(entry.getUserSentiment(), Ranking.USER_SENTIMENT_NEUTRAL);
     }
 
     @Test
-    @Ignore
-    public void testUpdateNotification() throws Exception {
-        TestableLooper.get(this).processAllMessages();
-
+    public void testUpdateNotification_updatesUserSentiment() {
         mEntryManager.addActiveNotificationForTest(mEntry);
-
         setUserSentiment(
                 mEntry.getKey(), Ranking.USER_SENTIMENT_NEGATIVE);
 
         mEntryManager.updateNotification(mSbn, mRankingMap);
-        TestableLooper.get(this).processMessages(1);
-        // Wait for content update.
-        assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS));
 
-        verify(mEntryListener, never()).onInflationError(any(), any());
-
-        verify(mEntryListener).onPreEntryUpdated(mEntry);
-        verify(mPresenter).updateNotificationViews();
-        verify(mEntryListener).onPostEntryUpdated(mEntry);
-
-        assertNotNull(mEntry.getRow());
-        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE,
-                mEntry.getUserSentiment());
+        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, mEntry.getUserSentiment());
     }
 
     @Test
-    @Ignore
     public void testUpdateNotification_prePostEntryOrder() throws Exception {
         TestableLooper.get(this).processAllMessages();
 
         mEntryManager.addActiveNotificationForTest(mEntry);
 
         mEntryManager.updateNotification(mSbn, mRankingMap);
-        TestableLooper.get(this).processMessages(1);
-        // Wait for content update.
-        assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS));
-
-        verify(mEntryListener, never()).onInflationError(any(), any());
 
         // Ensure that update callbacks happen in correct order
         InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener);
         order.verify(mEntryListener).onPreEntryUpdated(mEntry);
         order.verify(mPresenter).updateNotificationViews();
         order.verify(mEntryListener).onPostEntryUpdated(mEntry);
-
-        assertNotNull(mEntry.getRow());
     }
 
     @Test
@@ -414,8 +252,6 @@
 
         mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
 
-        verify(mEntryListener, never()).onInflationError(any(), any());
-
         verify(mPresenter).updateNotificationViews();
         verify(mEntryListener).onEntryRemoved(
                 eq(mEntry), any(), eq(false) /* removedByUser */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
new file mode 100644
index 0000000..ac40808
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+
+import static junit.framework.Assert.assertNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.Handler;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.NotificationMessagingUtil;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.SbnBuilder;
+import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
+import com.android.systemui.statusbar.notification.NotificationClicker;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
+import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
+import com.android.systemui.util.leak.LeakDetector;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+/**
+ * Functional tests for notification inflation from {@link NotificationEntryManager}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class NotificationEntryManagerInflationTest extends SysuiTestCase {
+
+    private static final String TEST_TITLE = "Title";
+    private static final String TEST_TEXT = "Text";
+    private static final long TIMEOUT_TIME = 10000;
+    private static final Runnable TIMEOUT_RUNNABLE = () -> {
+        throw new RuntimeException("Timed out waiting to inflate");
+    };
+
+    @Mock private NotificationPresenter mPresenter;
+    @Mock private NotificationEntryManager.KeyguardEnvironment mEnvironment;
+    @Mock private NotificationListContainer mListContainer;
+    @Mock private NotificationEntryListener mEntryListener;
+    @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
+    @Mock private HeadsUpManager mHeadsUpManager;
+    @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+    @Mock private NotificationGutsManager mGutsManager;
+    @Mock private NotificationRemoteInputManager mRemoteInputManager;
+    @Mock private NotificationMediaManager mNotificationMediaManager;
+    @Mock private ExpandableNotificationRowComponent.Builder
+            mExpandableNotificationRowComponentBuilder;
+    @Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent;
+    @Mock private FalsingManager mFalsingManager;
+    @Mock private KeyguardBypassController mKeyguardBypassController;
+    @Mock private StatusBarStateController mStatusBarStateController;
+
+    @Mock private NotificationGroupManager mGroupManager;
+    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private LeakDetector mLeakDetector;
+
+    @Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
+    @Mock private NotificationRowComponent.Builder mNotificationRowComponentBuilder;
+
+    private StatusBarNotification mSbn;
+    private NotificationListenerService.RankingMap mRankingMap;
+    private NotificationEntryManager mEntryManager;
+    private NotificationRowBinderImpl mRowBinder;
+    private Handler mHandler;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mDependency.injectMockDependency(SmartReplyController.class);
+
+        mHandler = Handler.createAsync(TestableLooper.get(this).getLooper());
+
+        Notification notification = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle(TEST_TITLE)
+                .setContentText(TEST_TEXT)
+                .build();
+        mSbn = new SbnBuilder()
+                .setNotification(notification)
+                .build();
+
+        when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
+        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
+
+        mEntryManager = new NotificationEntryManager(
+                mock(NotificationEntryManagerLogger.class),
+                mGroupManager,
+                new NotificationRankingManager(
+                        () -> mock(NotificationMediaManager.class),
+                        mGroupManager,
+                        mHeadsUpManager,
+                        mock(NotificationFilter.class),
+                        mock(NotificationEntryManagerLogger.class),
+                        mock(NotificationSectionsFeatureManager.class),
+                        mock(PeopleNotificationIdentifier.class),
+                        mock(HighPriorityProvider.class)),
+                mEnvironment,
+                mFeatureFlags,
+                () -> mRowBinder,
+                () -> mRemoteInputManager,
+                mLeakDetector,
+                mock(ForegroundServiceDismissalFeatureController.class)
+        );
+
+        NotifRemoteViewCache cache = new NotifRemoteViewCacheImpl(mEntryManager);
+        NotifBindPipeline pipeline = new NotifBindPipeline(
+                mEntryManager,
+                mock(NotifBindPipelineLogger.class));
+        NotificationContentInflater binder = new NotificationContentInflater(
+                cache,
+                mRemoteInputManager,
+                () -> mock(SmartReplyConstants.class),
+                () -> mock(SmartReplyController.class));
+        RowContentBindStage stage = new RowContentBindStage(
+                binder,
+                mock(NotifInflationErrorManager.class),
+                mock(RowContentBindStageLogger.class));
+        pipeline.setStage(stage);
+
+        ArgumentCaptor<ExpandableNotificationRow> viewCaptor =
+                ArgumentCaptor.forClass(ExpandableNotificationRow.class);
+        when(mExpandableNotificationRowComponentBuilder
+                .expandableNotificationRow(viewCaptor.capture()))
+                .thenReturn(mExpandableNotificationRowComponentBuilder);
+        when(mExpandableNotificationRowComponentBuilder
+                .notificationEntry(any()))
+                .thenReturn(mExpandableNotificationRowComponentBuilder);
+        when(mExpandableNotificationRowComponentBuilder
+                .onDismissRunnable(any()))
+                .thenReturn(mExpandableNotificationRowComponentBuilder);
+        when(mExpandableNotificationRowComponentBuilder
+                .inflationCallback(any()))
+                .thenReturn(mExpandableNotificationRowComponentBuilder);
+        when(mExpandableNotificationRowComponentBuilder
+                .rowContentBindStage(any()))
+                .thenReturn(mExpandableNotificationRowComponentBuilder);
+        when(mExpandableNotificationRowComponentBuilder
+                .onExpandClickListener(any()))
+                .thenReturn(mExpandableNotificationRowComponentBuilder);
+
+        when(mExpandableNotificationRowComponentBuilder.build())
+                .thenReturn(mExpandableNotificationRowComponent);
+        when(mExpandableNotificationRowComponent.getExpandableNotificationRowController())
+                .thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
+                        new ExpandableNotificationRowController(
+                                viewCaptor.getValue(),
+                                mock(ActivatableNotificationViewController.class),
+                                mNotificationMediaManager,
+                                mock(PluginManager.class),
+                                new FakeSystemClock(),
+                                "FOOBAR", "FOOBAR",
+                                mKeyguardBypassController,
+                                mGroupManager,
+                                stage,
+                                mock(NotificationLogger.class),
+                                mHeadsUpManager,
+                                mPresenter,
+                                mStatusBarStateController,
+                                mEntryManager,
+                                mGutsManager,
+                                true,
+                                null,
+                                mFalsingManager
+                        ));
+
+        when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
+                .thenReturn(mNotificationRowComponentBuilder);
+        when(mNotificationRowComponentBuilder.build()).thenReturn(
+                () -> mActivatableNotificationViewController);
+
+        mRowBinder = new NotificationRowBinderImpl(
+                mContext,
+                new NotificationMessagingUtil(mContext),
+                mRemoteInputManager,
+                mLockscreenUserManager,
+                pipeline,
+                stage,
+                true, /* allowLongPress */
+                mock(KeyguardBypassController.class),
+                mock(StatusBarStateController.class),
+                mGroupManager,
+                mGutsManager,
+                mNotificationInterruptionStateProvider,
+                RowInflaterTask::new,
+                mExpandableNotificationRowComponentBuilder);
+
+        mEntryManager.setUpWithPresenter(mPresenter);
+        mEntryManager.addNotificationEntryListener(mEntryListener);
+
+        mRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback);
+        mRowBinder.setInflationCallback(mEntryManager);
+        mRowBinder.setNotificationClicker(mock(NotificationClicker.class));
+
+        Ranking ranking = new Ranking();
+        ranking.populate(
+                mSbn.getKey(),
+                0,
+                false,
+                0,
+                0,
+                IMPORTANCE_DEFAULT,
+                null,
+                null,
+                null,
+                null,
+                null,
+                true,
+                Ranking.USER_SENTIMENT_NEUTRAL,
+                false,
+                -1,
+                false,
+                null,
+                null,
+                false,
+                false,
+                false);
+        mRankingMap = new NotificationListenerService.RankingMap(new Ranking[] {ranking});
+
+        TestableLooper.get(this).processAllMessages();
+    }
+
+    @After
+    public void cleanUp() {
+        // Don't leave anything on main thread
+        TestableLooper.get(this).processAllMessages();
+    }
+
+    @Test
+    public void testAddNotification() {
+        // WHEN a notification is added
+        mEntryManager.addNotification(mSbn, mRankingMap);
+        ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass(
+                NotificationEntry.class);
+        verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
+        NotificationEntry entry = entryCaptor.getValue();
+
+        // Wait for inflation
+        // row inflation, system notification, remote views, contracted view
+        waitForMessages(4);
+
+        // THEN the notification has its row inflated
+        assertNotNull(entry.getRow());
+        assertNotNull(entry.getRow().getPrivateLayout().getContractedChild());
+
+        // THEN inflation callbacks are called
+        verify(mBindCallback).onBindRow(eq(entry), any(), eq(mSbn), any());
+        verify(mEntryListener, never()).onInflationError(any(), any());
+        verify(mEntryListener).onEntryInflated(entry);
+        verify(mEntryListener).onNotificationAdded(entry);
+
+        // THEN the notification is active
+        assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
+
+        // THEN we update the presenter
+        verify(mPresenter).updateNotificationViews();
+    }
+
+    @Test
+    public void testUpdateNotification() {
+        // GIVEN a notification already added
+        mEntryManager.addNotification(mSbn, mRankingMap);
+        ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass(
+                NotificationEntry.class);
+        verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
+        NotificationEntry entry = entryCaptor.getValue();
+        waitForMessages(4);
+
+        Mockito.reset(mEntryListener);
+        Mockito.reset(mPresenter);
+
+        // WHEN the notification is updated
+        mEntryManager.updateNotification(mSbn, mRankingMap);
+
+        // Wait for inflation
+        // remote views, contracted view
+        waitForMessages(2);
+
+        // THEN the notification has its row and inflated
+        assertNotNull(entry.getRow());
+
+        // THEN inflation callbacks are called
+        verify(mEntryListener, never()).onInflationError(any(), any());
+        verify(mEntryListener).onEntryReinflated(entry);
+
+        // THEN we update the presenter
+        verify(mPresenter).updateNotificationViews();
+    }
+
+    /**
+     * Wait for a certain number of messages to finish before continuing, timing out if they never
+     * occur.
+     *
+     * As part of the inflation pipeline, the main thread is forced to deal with several callbacks
+     * due to the nature of the API used (generally because they're {@link android.os.AsyncTask}
+     * callbacks). In order, these are
+     *
+     * 1) Callback after row inflation. See {@link RowInflaterTask}.
+     * 2) Callback checking if row is system notification. See
+     *    {@link ExpandableNotificationRow#setEntry}
+     * 3) Callback after remote views are created. See
+     *    {@link NotificationContentInflater.AsyncInflationTask}.
+     * 4-6) Callback after each content view is inflated/rebound from remote view. See
+     *      {@link NotificationContentInflater#applyRemoteView} and {@link InflationFlag}.
+     *
+     * Depending on the test, only some of these will be necessary. For example, generally, not
+     * every content view is inflated or the row may not be inflated if one already exists.
+     *
+     * Currently, the burden is on the developer to figure these out until we have a much more
+     * test-friendly way of executing inflation logic (i.e. pass in an executor).
+     */
+    private void waitForMessages(int numMessages) {
+        mHandler.postDelayed(TIMEOUT_RUNNABLE, TIMEOUT_TIME);
+        TestableLooper.get(this).processMessages(numMessages);
+        mHandler.removeCallbacks(TIMEOUT_RUNNABLE);
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
index 7d52df7..2782f3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
@@ -32,6 +32,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -58,6 +59,7 @@
     @Mock private KeyguardBypassController mKeyguardBypassController;
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock ColorExtractor.GradientColors mGradientColors;
+    @Mock private DumpController mDumpController;
 
     private NotificationShadeWindowController mNotificationShadeWindowController;
 
@@ -69,7 +71,8 @@
 
         mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
                 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController, mColorExtractor);
+                mConfigurationController, mKeyguardBypassController, mColorExtractor,
+                mDumpController);
         mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
 
         mNotificationShadeWindowController.attach();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3b0a1a3..d86b223 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2120,8 +2120,6 @@
 
     private void unmount(VolumeInfo vol) {
         try {
-            mVold.unmount(vol.id);
-            mStorageSessionController.onVolumeUnmount(vol);
             try {
                 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
                     mInstaller.onPrivateVolumeRemoved(vol.getFsUuid());
@@ -2129,6 +2127,8 @@
             } catch (Installer.InstallerException e) {
                 Slog.e(TAG, "Failed unmount mirror data", e);
             }
+            mVold.unmount(vol.id);
+            mStorageSessionController.onVolumeUnmount(vol);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
@@ -4346,6 +4346,42 @@
             mPolicies.add(policy);
         }
 
+        /**
+         * Check if fuse is running in target user, if it's running then setup its obb directories.
+         * TODO: System server should store a list of active pids that obb is not mounted and use it.
+         */
+        @Override
+        public void prepareObbDirs(int userId, Set<String> packageList, String processName) {
+            String fuseRunningUsersList = SystemProperties.get("vold.fuse_running_users", "");
+            String[] fuseRunningUsers = fuseRunningUsersList.split(",");
+            boolean fuseReady = false;
+            String targetUserId = String.valueOf(userId);
+            for (String user : fuseRunningUsers) {
+                if (targetUserId.equals(user)) {
+                    fuseReady = true;
+                }
+            }
+            if (fuseReady) {
+                try {
+                    final IVold vold = IVold.Stub.asInterface(
+                            ServiceManager.getServiceOrThrow("vold"));
+                    for (String pkg : packageList) {
+                        final String obbDir =
+                                String.format("/storage/emulated/%d/Android/obb", userId);
+                        final String packageObbDir = String.format("%s/%s/", obbDir, pkg);
+
+                        // Create package obb dir if it doesn't exist.
+                        File file = new File(packageObbDir);
+                        if (!file.exists()) {
+                            vold.setupAppDir(packageObbDir, mPmInternal.getPackage(pkg).getUid());
+                        }
+                    }
+                } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
+                    Slog.e(TAG, "Unable to create obb directories for " + processName, e);
+                }
+            }
+        }
+
         @Override
         public void onExternalStoragePolicyChanged(int uid, String packageName) {
             final int mountMode = getExternalStorageMountMode(uid, packageName);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ffa7d92..0dc44f7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -80,11 +80,13 @@
 import android.os.DropBoxManager;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IVold;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -142,10 +144,14 @@
 public final class ProcessList {
     static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
 
-    // A device config to control the minimum target SDK to enable app data isolation
+    // A system property to control if app data isolation is enabled.
     static final String ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
             "persist.zygote.app_data_isolation";
 
+    // A system property to control if obb app data isolation is enabled in vold.
+    static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+            "persist.sys.vold_app_data_isolation_enabled";
+
     // A device config to control the minimum target SDK to enable app data isolation
     static final String ANDROID_APP_DATA_ISOLATION_MIN_SDK = "android_app_data_isolation_min_sdk";
 
@@ -379,6 +385,8 @@
 
     private boolean mAppDataIsolationEnabled = false;
 
+    private boolean mVoldAppDataIsolationEnabled = false;
+
     private ArrayList<String> mAppDataIsolationWhitelistedApps;
 
     /**
@@ -691,6 +699,8 @@
         // want some apps enabled while some apps disabled
         mAppDataIsolationEnabled =
                 SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+        mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
+                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
         mAppDataIsolationWhitelistedApps = new ArrayList<>(
                 SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
 
@@ -2113,6 +2123,13 @@
                         app.info.packageName, app.userId);
                 pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0
                         ? new String[]{app.info.packageName} : sharedPackages, uid);
+
+                if (mVoldAppDataIsolationEnabled) {
+                    StorageManagerInternal storageManagerInternal = LocalServices.getService(
+                                StorageManagerInternal.class);
+                    storageManagerInternal.prepareObbDirs(UserHandle.getUserId(uid),
+                            pkgDataInfoMap.keySet(), app.processName);
+                }
             } else {
                 pkgDataInfoMap = null;
             }
diff --git a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java
index 09af655..bc50ebc 100644
--- a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java
+++ b/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java
@@ -20,7 +20,6 @@
 import android.location.GnssAntennaInfo;
 import android.location.IGnssAntennaInfoListener;
 import android.os.Handler;
-import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -100,41 +99,10 @@
 
     @Override
     protected ListenerOperation<IGnssAntennaInfoListener> getHandlerOperation(int result) {
-        int status;
-        switch (result) {
-            case RESULT_SUCCESS:
-                status = GnssAntennaInfo.Callback.STATUS_READY;
-                break;
-            case RESULT_NOT_AVAILABLE:
-            case RESULT_NOT_SUPPORTED:
-            case RESULT_INTERNAL_ERROR:
-                status = GnssAntennaInfo.Callback.STATUS_NOT_SUPPORTED;
-                break;
-            case RESULT_GPS_LOCATION_DISABLED:
-                status = GnssAntennaInfo.Callback.STATUS_LOCATION_DISABLED;
-                break;
-            case RESULT_UNKNOWN:
-                return null;
-            default:
-                Log.v(TAG, "Unhandled addListener result: " + result);
-                return null;
-        }
-        return new StatusChangedOperation(status);
-    }
-
-    private static class StatusChangedOperation
-            implements ListenerOperation<IGnssAntennaInfoListener> {
-        private final int mStatus;
-
-        StatusChangedOperation(int status) {
-            mStatus = status;
-        }
-
-        @Override
-        public void execute(IGnssAntennaInfoListener listener,
-                CallerIdentity callerIdentity) throws RemoteException {
-            listener.onStatusChanged(mStatus);
-        }
+        return (IGnssAntennaInfoListener listener,
+                CallerIdentity callerIdentity) -> {
+                // Do nothing, as GnssAntennaInfo.Callback does not have an onStatusChanged method.
+        };
     }
 
     /** Handle Gnss Antenna Info report. */
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 36136f4..5f44e04 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -2244,6 +2244,7 @@
         if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
             s.append("MEASUREMENT_CORRECTIONS ");
         }
+        if (hasCapability(GPS_CAPABILITY_ANTENNA_INFO)) s.append("ANTENNA_INFO ");
         s.append(")\n");
         if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
             s.append("SubHal=MEASUREMENT_CORRECTIONS[");
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 1039cf6..b57c261 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -216,9 +216,6 @@
      * {@link android.location.GnssCapabilities}.
      */
     public long getGnssCapabilities(String packageName) {
-        mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
-        mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
-
         if (!checkLocationAppOp(packageName)) {
             return GnssCapabilities.INVALID_CAPABILITIES;
         }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 3a16217..09e3feb 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -16,7 +16,6 @@
 
 package com.android.server.pm;
 
-import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -307,8 +306,8 @@
             final int callingUserId = injectCallingUserId();
 
             if (targetUserId == callingUserId) return true;
-            if (mContext.checkCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL)
-                    == PackageManager.PERMISSION_GRANTED) {
+            if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(),
+                    injectBinderCallingUid())) {
                 return true;
             }
 
@@ -684,6 +683,15 @@
                     callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
         }
 
+        /**
+         * Returns true if the caller has the "INTERACT_ACROSS_USERS_FULL" permission.
+         */
+        @VisibleForTesting
+        boolean injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid) {
+            return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+        }
+
         @Override
         public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
                 String packageName, List shortcutIds, List<LocusId> locusIds,
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e6eaf21..9c945d5 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -150,6 +150,12 @@
         ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
     }
 
+    private static final Set<String> FOREGROUND_LOCATION_PERMISSIONS = new ArraySet<>();
+    static {
+        ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
+        ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
+    }
+
     private static final Set<String> COARSE_BACKGROUND_LOCATION_PERMISSIONS = new ArraySet<>();
     static {
         COARSE_BACKGROUND_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
@@ -587,11 +593,6 @@
                         DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
                 userId, CONTACTS_PERMISSIONS);
 
-        // Maps
-        grantPermissionsToSystemPackage(
-                getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId),
-                userId, ALWAYS_LOCATION_PERMISSIONS);
-
         // Email
         grantPermissionsToSystemPackage(
                 getDefaultSystemHandlerActivityPackageForCategory(
@@ -609,7 +610,7 @@
             }
         }
         grantPermissionsToPackage(browserPackage, userId, false /* ignoreSystemPackage */,
-                true /*whitelistRestrictedPermissions*/, ALWAYS_LOCATION_PERMISSIONS);
+                true /*whitelistRestrictedPermissions*/, FOREGROUND_LOCATION_PERMISSIONS);
 
         // Voice interaction
         if (voiceInteractPackageNames != null) {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e1615af..36ed9a5 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -55,10 +55,9 @@
 static jclass class_gnssNavigationMessage;
 static jclass class_gnssClock;
 static jclass class_gnssConfiguration_halInterfaceVersion;
-static jclass class_gnssAntennaInfo;
-static jclass class_phaseCenterOffsetCoordinates;
-static jclass class_phaseCenterVariationCorrections;
-static jclass class_signalGainCorrections;
+static jclass class_gnssAntennaInfoBuilder;
+static jclass class_phaseCenterOffset;
+static jclass class_sphericalCorrections;
 static jclass class_arrayList;
 static jclass class_doubleArray;
 
@@ -122,12 +121,16 @@
 static jmethodID method_gnssClockCtor;
 static jmethodID method_gnssMeasurementCtor;
 static jmethodID method_halInterfaceVersionCtor;
-static jmethodID method_gnssAntennaInfoCtor;
-static jmethodID method_phaseCenterOffsetCoordinatesCtor;
-static jmethodID method_phaseCenterVariationCorrectionsCtor;
-static jmethodID method_signalGainCorrectionsCtor;
+static jmethodID method_gnssAntennaInfoBuilderCtor;
+static jmethodID method_phaseCenterOffsetCtor;
+static jmethodID method_sphericalCorrectionsCtor;
 static jmethodID method_arrayListCtor;
 static jmethodID method_arrayListAdd;
+static jmethodID method_gnssAntennaInfoBuilderSetCarrierFrequencyMHz;
+static jmethodID method_gnssAntennaInfoBuilderSetPhaseCenterOffset;
+static jmethodID method_gnssAntennaInfoBuilderSetPhaseCenterVariationCorrections;
+static jmethodID method_gnssAntennaInfoBuilderSetSignalGainCorrections;
+static jmethodID method_gnssAntennaInfoBuilderBuild;
 
 /*
  * Save a pointer to JavaVm to attach/detach threads executing
@@ -1088,7 +1091,7 @@
             const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
     jobject translateSingleGnssAntennaInfo(
             JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo);
-    jobject translatePhaseCenterOffsetCoordinates(
+    jobject translatePhaseCenterOffset(
             JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo);
     jobject translatePhaseCenterVariationCorrections(
             JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo);
@@ -1150,11 +1153,10 @@
     return arrayList;
 }
 
-jobject GnssAntennaInfoCallback::translatePhaseCenterOffsetCoordinates(
+jobject GnssAntennaInfoCallback::translatePhaseCenterOffset(
         JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) {
-    jobject phaseCenterOffsetCoordinates =
-            env->NewObject(class_phaseCenterOffsetCoordinates,
-                           method_phaseCenterOffsetCoordinatesCtor,
+    jobject phaseCenterOffset =
+            env->NewObject(class_phaseCenterOffset, method_phaseCenterOffsetCtor,
                            gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.x,
                            gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.xUncertainty,
                            gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.y,
@@ -1162,7 +1164,7 @@
                            gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.z,
                            gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.zUncertainty);
 
-    return phaseCenterOffsetCoordinates;
+    return phaseCenterOffset;
 }
 
 jobject GnssAntennaInfoCallback::translatePhaseCenterVariationCorrections(
@@ -1185,8 +1187,7 @@
     }
 
     jobject phaseCenterVariationCorrections =
-            env->NewObject(class_phaseCenterVariationCorrections,
-                           method_phaseCenterVariationCorrectionsCtor,
+            env->NewObject(class_sphericalCorrections, method_sphericalCorrectionsCtor,
                            phaseCenterVariationCorrectionsArray,
                            phaseCenterVariationCorrectionsUncertaintiesArray);
 
@@ -1212,7 +1213,7 @@
     }
 
     jobject signalGainCorrections =
-            env->NewObject(class_signalGainCorrections, method_signalGainCorrectionsCtor,
+            env->NewObject(class_sphericalCorrections, method_sphericalCorrectionsCtor,
                            signalGainCorrectionsArray, signalGainCorrectionsUncertaintiesArray);
 
     env->DeleteLocalRef(signalGainCorrectionsArray);
@@ -1223,8 +1224,7 @@
 
 jobject GnssAntennaInfoCallback::translateSingleGnssAntennaInfo(
         JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) {
-    jobject phaseCenterOffsetCoordinates =
-            translatePhaseCenterOffsetCoordinates(env, gnssAntennaInfo);
+    jobject phaseCenterOffset = translatePhaseCenterOffset(env, gnssAntennaInfo);
 
     // Nullable
     jobject phaseCenterVariationCorrections =
@@ -1233,13 +1233,29 @@
     // Nullable
     jobject signalGainCorrections = translateSignalGainCorrections(env, gnssAntennaInfo);
 
+    // Get builder
+    jobject gnssAntennaInfoBuilderObject =
+            env->NewObject(class_gnssAntennaInfoBuilder, method_gnssAntennaInfoBuilderCtor);
+
+    // Set fields
+    env->CallObjectMethod(gnssAntennaInfoBuilderObject,
+                          method_gnssAntennaInfoBuilderSetCarrierFrequencyMHz,
+                          gnssAntennaInfo.carrierFrequencyMHz);
+    env->CallObjectMethod(gnssAntennaInfoBuilderObject,
+                          method_gnssAntennaInfoBuilderSetPhaseCenterOffset, phaseCenterOffset);
+    env->CallObjectMethod(gnssAntennaInfoBuilderObject,
+                          method_gnssAntennaInfoBuilderSetPhaseCenterVariationCorrections,
+                          phaseCenterVariationCorrections);
+    env->CallObjectMethod(gnssAntennaInfoBuilderObject,
+                          method_gnssAntennaInfoBuilderSetSignalGainCorrections,
+                          signalGainCorrections);
+
+    // build
     jobject gnssAntennaInfoObject =
-            env->NewObject(class_gnssAntennaInfo, method_gnssAntennaInfoCtor,
-                           gnssAntennaInfo.carrierFrequencyMHz, phaseCenterOffsetCoordinates,
-                           phaseCenterVariationCorrections, signalGainCorrections);
+            env->CallObjectMethod(gnssAntennaInfoBuilderObject, method_gnssAntennaInfoBuilderBuild);
 
     // Delete Local Refs
-    env->DeleteLocalRef(phaseCenterOffsetCoordinates);
+    env->DeleteLocalRef(phaseCenterOffset);
     env->DeleteLocalRef(phaseCenterVariationCorrections);
     env->DeleteLocalRef(signalGainCorrections);
 
@@ -2004,35 +2020,38 @@
     class_gnssMeasurement = (jclass) env->NewGlobalRef(gnssMeasurementClass);
     method_gnssMeasurementCtor = env->GetMethodID(class_gnssMeasurement, "<init>", "()V");
 
-    jclass gnssAntennaInfoClass = env->FindClass("android/location/GnssAntennaInfo");
-    class_gnssAntennaInfo = (jclass)env->NewGlobalRef(gnssAntennaInfoClass);
-    method_gnssAntennaInfoCtor =
-            env->GetMethodID(class_gnssAntennaInfo, "<init>",
-                             "(D"
-                             "Landroid/location/GnssAntennaInfo$PhaseCenterOffsetCoordinates;"
-                             "Landroid/location/GnssAntennaInfo$PhaseCenterVariationCorrections;"
-                             "Landroid/location/GnssAntennaInfo$SignalGainCorrections;"
-                             ")V");
+    jclass gnssAntennaInfoBuilder = env->FindClass("android/location/GnssAntennaInfo$Builder");
+    class_gnssAntennaInfoBuilder = (jclass)env->NewGlobalRef(gnssAntennaInfoBuilder);
+    method_gnssAntennaInfoBuilderCtor =
+            env->GetMethodID(class_gnssAntennaInfoBuilder, "<init>", "()V");
+    method_gnssAntennaInfoBuilderSetCarrierFrequencyMHz =
+            env->GetMethodID(class_gnssAntennaInfoBuilder, "setCarrierFrequencyMHz",
+                             "(D)Landroid/location/GnssAntennaInfo$Builder;");
+    method_gnssAntennaInfoBuilderSetPhaseCenterOffset =
+            env->GetMethodID(class_gnssAntennaInfoBuilder, "setPhaseCenterOffset",
+                             "(Landroid/location/GnssAntennaInfo$PhaseCenterOffset;)"
+                             "Landroid/location/GnssAntennaInfo$Builder;");
+    method_gnssAntennaInfoBuilderSetPhaseCenterVariationCorrections =
+            env->GetMethodID(class_gnssAntennaInfoBuilder, "setPhaseCenterVariationCorrections",
+                             "(Landroid/location/GnssAntennaInfo$SphericalCorrections;)"
+                             "Landroid/location/GnssAntennaInfo$Builder;");
+    method_gnssAntennaInfoBuilderSetSignalGainCorrections =
+            env->GetMethodID(class_gnssAntennaInfoBuilder, "setSignalGainCorrections",
+                             "(Landroid/location/GnssAntennaInfo$SphericalCorrections;)"
+                             "Landroid/location/GnssAntennaInfo$Builder;");
+    method_gnssAntennaInfoBuilderBuild = env->GetMethodID(class_gnssAntennaInfoBuilder, "build",
+                                                          "()Landroid/location/GnssAntennaInfo;");
 
-    jclass phaseCenterOffsetCoordinatesClass =
-            env->FindClass("android/location/GnssAntennaInfo$PhaseCenterOffsetCoordinates");
-    class_phaseCenterOffsetCoordinates =
-            (jclass)env->NewGlobalRef(phaseCenterOffsetCoordinatesClass);
-    method_phaseCenterOffsetCoordinatesCtor =
-            env->GetMethodID(class_phaseCenterOffsetCoordinates, "<init>", "(DDDDDD)V");
+    jclass phaseCenterOffsetClass =
+            env->FindClass("android/location/GnssAntennaInfo$PhaseCenterOffset");
+    class_phaseCenterOffset = (jclass)env->NewGlobalRef(phaseCenterOffsetClass);
+    method_phaseCenterOffsetCtor = env->GetMethodID(class_phaseCenterOffset, "<init>", "(DDDDDD)V");
 
-    jclass phaseCenterVariationCorrectionsClass =
-            env->FindClass("android/location/GnssAntennaInfo$PhaseCenterVariationCorrections");
-    class_phaseCenterVariationCorrections =
-            (jclass)env->NewGlobalRef(phaseCenterVariationCorrectionsClass);
-    method_phaseCenterVariationCorrectionsCtor =
-            env->GetMethodID(class_phaseCenterVariationCorrections, "<init>", "([[D[[D)V");
-
-    jclass signalGainCorrectionsClass =
-            env->FindClass("android/location/GnssAntennaInfo$SignalGainCorrections");
-    class_signalGainCorrections = (jclass)env->NewGlobalRef(signalGainCorrectionsClass);
-    method_signalGainCorrectionsCtor =
-            env->GetMethodID(class_signalGainCorrections, "<init>", "([[D[[D)V");
+    jclass sphericalCorrectionsClass =
+            env->FindClass("android/location/GnssAntennaInfo$SphericalCorrections");
+    class_sphericalCorrections = (jclass)env->NewGlobalRef(sphericalCorrectionsClass);
+    method_sphericalCorrectionsCtor =
+            env->GetMethodID(class_sphericalCorrections, "<init>", "([[D[[D)V");
 
     jclass locationClass = env->FindClass("android/location/Location");
     class_location = (jclass) env->NewGlobalRef(locationClass);
diff --git a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
index 19cbb0e..a99c982 100644
--- a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
@@ -38,6 +38,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.location.GnssAntennaInfo;
+import android.location.GnssAntennaInfo.SphericalCorrections;
 import android.location.GnssClock;
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementsEvent;
@@ -245,8 +246,8 @@
     private static List<GnssAntennaInfo> createDummyGnssAntennaInfos() {
         double carrierFrequencyMHz = 13758.0;
 
-        GnssAntennaInfo.PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates = new
-                GnssAntennaInfo.PhaseCenterOffsetCoordinates(
+        GnssAntennaInfo.PhaseCenterOffset phaseCenterOffset = new
+                GnssAntennaInfo.PhaseCenterOffset(
                 4.3d,
                 1.4d,
                 2.10d,
@@ -256,22 +257,26 @@
 
         double[][] phaseCenterVariationCorrectionsMillimeters = new double[10][10];
         double[][] phaseCenterVariationCorrectionsUncertaintyMillimeters = new double[10][10];
-        GnssAntennaInfo.PhaseCenterVariationCorrections
+        SphericalCorrections
                 phaseCenterVariationCorrections =
-                new GnssAntennaInfo.PhaseCenterVariationCorrections(
+                new SphericalCorrections(
                         phaseCenterVariationCorrectionsMillimeters,
                         phaseCenterVariationCorrectionsUncertaintyMillimeters);
 
         double[][] signalGainCorrectionsDbi = new double[10][10];
         double[][] signalGainCorrectionsUncertaintyDbi = new double[10][10];
-        GnssAntennaInfo.SignalGainCorrections signalGainCorrections = new
-                GnssAntennaInfo.SignalGainCorrections(
+        SphericalCorrections signalGainCorrections = new
+                SphericalCorrections(
                 signalGainCorrectionsDbi,
                 signalGainCorrectionsUncertaintyDbi);
 
         List<GnssAntennaInfo> gnssAntennaInfos = new ArrayList();
-        gnssAntennaInfos.add(new GnssAntennaInfo(carrierFrequencyMHz, phaseCenterOffsetCoordinates,
-                phaseCenterVariationCorrections, signalGainCorrections));
+        gnssAntennaInfos.add(new GnssAntennaInfo.Builder()
+                .setCarrierFrequencyMHz(carrierFrequencyMHz)
+                .setPhaseCenterOffset(phaseCenterOffset)
+                .setPhaseCenterVariationCorrections(phaseCenterVariationCorrections)
+                .setSignalGainCorrections(signalGainCorrections)
+                .build());
         return gnssAntennaInfos;
     }
 
@@ -388,14 +393,6 @@
     }
 
     @Test
-    public void getGnssCapabilitiesWithoutPermissionsTest() {
-        disableLocationPermissions();
-
-        assertThrows(SecurityException.class,
-                () -> mGnssManagerService.getGnssCapabilities("com.android.server"));
-    }
-
-    @Test
     public void getGnssCapabilitiesWithPermissionsTest() {
         final long mGnssCapabilities = 23132L;
         when(mMockGnssCapabilitiesProvider.getGnssCapabilities()).thenReturn(mGnssCapabilities);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index df2b3ef..6c769485 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -562,6 +562,11 @@
         boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
             return true;
         }
+
+        @Override
+        boolean injectHasInteractAcrossUsersFullPermission(int callingPid, int callingUid) {
+            return false;
+        }
     }
 
     protected class LauncherAppsTestable extends LauncherApps {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index df5b311..0d1b352 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -86,6 +86,7 @@
 
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
@@ -104,6 +105,7 @@
 import java.io.PrintWriter;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -1121,7 +1123,7 @@
 
             boolean checkin = false;
             boolean compact = false;
-            String pkg = null;
+            final ArrayList<String> pkgs = new ArrayList<>();
 
             if (args != null) {
                 for (int i = 0; i < args.length; i++) {
@@ -1214,8 +1216,7 @@
                         return;
                     } else if (arg != null && !arg.startsWith("-")) {
                         // Anything else that doesn't start with '-' is a pkg to filter
-                        pkg = arg;
-                        break;
+                        pkgs.add(arg);
                     }
                 }
             }
@@ -1230,15 +1231,15 @@
                     if (checkin) {
                         mUserState.valueAt(i).checkin(idpw);
                     } else {
-                        mUserState.valueAt(i).dump(idpw, pkg, compact);
+                        mUserState.valueAt(i).dump(idpw, pkgs, compact);
                         idpw.println();
                     }
                 }
-                mAppStandby.dumpUser(idpw, userId, pkg);
+                mAppStandby.dumpUser(idpw, userId, pkgs);
                 idpw.decreaseIndent();
             }
 
-            if (pkg == null) {
+            if (CollectionUtils.isEmpty(pkgs)) {
                 pw.println();
                 mAppStandby.dumpState(args, pw);
             }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index db26d88..b7779fd 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -48,6 +48,7 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.usage.UsageStatsDatabase.StatCombiner;
 
@@ -753,18 +754,21 @@
         });
     }
 
-    void dump(IndentingPrintWriter pw, String pkg) {
-        dump(pw, pkg, false);
+    void dump(IndentingPrintWriter pw, List<String> pkgs) {
+        dump(pw, pkgs, false);
     }
-    void dump(IndentingPrintWriter pw, String pkg, boolean compact) {
-        printLast24HrEvents(pw, !compact, pkg);
+
+    void dump(IndentingPrintWriter pw, List<String> pkgs, boolean compact) {
+        printLast24HrEvents(pw, !compact, pkgs);
         for (int interval = 0; interval < mCurrentStats.length; interval++) {
             pw.print("In-memory ");
             pw.print(intervalToString(interval));
             pw.println(" stats");
-            printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkg);
+            printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkgs);
         }
-        mDatabase.dump(pw, compact);
+        if (CollectionUtils.isEmpty(pkgs)) {
+            mDatabase.dump(pw, compact);
+        }
     }
 
     void dumpDatabaseInfo(IndentingPrintWriter ipw) {
@@ -894,7 +898,8 @@
         pw.println();
     }
 
-    void printLast24HrEvents(IndentingPrintWriter pw, boolean prettyDates, final String pkg) {
+    void printLast24HrEvents(IndentingPrintWriter pw, boolean prettyDates,
+            final List<String> pkgs) {
         final long endTime = System.currentTimeMillis();
         UnixCalendar yesterday = new UnixCalendar(endTime);
         yesterday.addDays(-1);
@@ -914,7 +919,7 @@
                             }
 
                             Event event = stats.events.get(i);
-                            if (pkg != null && !pkg.equals(event.mPackage)) {
+                            if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(event.mPackage)) {
                                 continue;
                             }
                             accumulatedResult.add(event);
@@ -958,7 +963,7 @@
     }
 
     void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
-            boolean prettyDates, boolean skipEvents, String pkg) {
+            boolean prettyDates, boolean skipEvents, List<String> pkgs) {
         if (prettyDates) {
             pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
                     stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
@@ -974,7 +979,7 @@
         final int pkgCount = pkgStats.size();
         for (int i = 0; i < pkgCount; i++) {
             final UsageStats usageStats = pkgStats.valueAt(i);
-            if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
+            if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(usageStats.mPackageName)) {
                 continue;
             }
             pw.printPair("package", usageStats.mPackageName);
@@ -998,7 +1003,7 @@
         pw.println("ChooserCounts");
         pw.increaseIndent();
         for (UsageStats usageStats : pkgStats.values()) {
-            if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
+            if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(usageStats.mPackageName)) {
                 continue;
             }
             pw.printPair("package", usageStats.mPackageName);
@@ -1023,7 +1028,7 @@
         }
         pw.decreaseIndent();
 
-        if (pkg == null) {
+        if (CollectionUtils.isEmpty(pkgs)) {
             pw.println("configurations");
             pw.increaseIndent();
             final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
@@ -1060,7 +1065,7 @@
             final int eventCount = events != null ? events.size() : 0;
             for (int i = 0; i < eventCount; i++) {
                 final Event event = events.get(i);
-                if (pkg != null && !pkg.equals(event.mPackage)) {
+                if (!CollectionUtils.isEmpty(pkgs) && !pkgs.contains(event.mPackage)) {
                     continue;
                 }
                 printEvent(pw, event, prettyDates);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 795de57..9924839c 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -17,7 +17,6 @@
 package android.telephony;
 
 import android.Manifest;
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -28,7 +27,6 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
-import android.net.ipsec.ike.SaProposal;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.service.carrier.CarrierService;
@@ -3499,369 +3497,6 @@
     public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL =
             "show_forwarded_number_bool";
 
-    /**
-     * Configs used for epdg tunnel bring up.
-     *
-     * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange
-     *        Protocol Version 2 (IKEv2)</a>
-     */
-    public static final class Iwlan {
-        /** Prefix of all Epdg.KEY_* constants. */
-        public static final String KEY_PREFIX = "iwlan.";
-
-        /**
-         * Time in seconds after which the child security association session is terminated if
-         * rekey procedure is not successful. If not set or set to <= 0, the default value is
-         * 3600 seconds.
-         */
-        public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT =
-                KEY_PREFIX + "child_sa_rekey_hard_timer_sec_int";
-
-        /**
-         * Time in seconds after which the child session rekey procedure is started. If not set or
-         * set to <= 0, default value is 3000 seconds.
-         */
-        public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT =
-                KEY_PREFIX + "child_sa_rekey_soft_timer_sec_int";
-
-        /** Supported DH groups for IKE negotiation.
-         * Possible values are {@link #DH_GROUP_NONE}, {@link #DH_GROUP_1024_BIT_MODP},
-         * {@link #DH_GROUP_2048_BIT_MODP}
-         */
-        public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY =
-                KEY_PREFIX + "diffie_hellman_groups_int_array";
-
-        /**
-         * Time in seconds after which a dead peer detection (DPD) request is sent.
-         * If not set or set to <= 0, default value is 120 seconds.
-         */
-        public static final String KEY_DPD_TIMER_SEC_INT = KEY_PREFIX + "dpd_timer_sec_int";
-
-        /**
-         * Method used to authenticate epdg server.
-         * Possible values are {@link #AUTHENTICATION_METHOD_EAP_ONLY},
-         * {@link #AUTHENTICATION_METHOD_CERT}
-         */
-        public static final String KEY_EPDG_AUTHENTICATION_METHOD_INT =
-                KEY_PREFIX + "epdg_authentication_method_int";
-
-        /**
-         * A priority list of ePDG addresses to be used.
-         * Possible values are {@link #EPDG_ADDRESS_STATIC}, {@link #EPDG_ADDRESS_PLMN},
-         * {@link #EPDG_ADDRESS_PCO}
-         */
-        public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY =
-                KEY_PREFIX + "epdg_address_priority_int_array";
-
-        /** Epdg static IP address or FQDN */
-        public static final String KEY_EPDG_STATIC_ADDRESS_STRING =
-                KEY_PREFIX + "epdg_static_address_string";
-
-        /** Epdg static IP address or FQDN for roaming */
-        public static final String KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING =
-                KEY_PREFIX + "epdg_static_address_roaming_string";
-
-        /**
-         * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of child
-         * session.
-         * Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
-         * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
-         */
-        public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
-                KEY_PREFIX + "child_session_aes_cbc_key_size_int_array";
-
-        /**
-         * List of supported key sizes for AES counter (CTR) encryption mode of child session.
-         * Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
-         * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
-         */
-        public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
-                KEY_PREFIX + "child_encryption_aes_ctr_key_size_int_array";
-
-        /**
-         * List of supported encryption algorithms for child session.
-         * Possible values are {@link #ENCRYPTION_ALGORITHM_3DES},
-         * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_8},
-         * {@link #ENCRYPTION_ALGORITHM_AES_GCM_12}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_16}
-         */
-        public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
-                KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array";
-
-        /** Controls if IKE message fragmentation is enabled. */
-        public static final String KEY_IKE_FRAGMENTATION_ENABLED_BOOL =
-                KEY_PREFIX + "ike_fragmentation_enabled_bool";
-
-        /**
-         * Time in seconds after which the IKE session is terminated if rekey procedure is not
-         * successful. If not set or set to <= 0, default value is 3600 seconds.
-         */
-        public static final String KEY_IKE_REKEY_HARD_TIMER_SEC_INT =
-                KEY_PREFIX + "ike_rekey_hard_timer_in_sec";
-
-        /**
-         * Time in seconds after which the IKE session rekey procedure is started. If not set or
-         * set to <= 0, default value is 3000 seconds.
-         */
-        public static final String KEY_IKE_REKEY_SOFT_TIMER_SEC_INT =
-                KEY_PREFIX + "ike_rekey_soft_timer_sec_int";
-
-        /**
-         * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of IKE
-         * session.
-         * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
-         *         {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
-         */
-        public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
-                KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array";
-
-        /**
-         * List of supported key sizes for AES counter (CTR) encryption mode of IKE session.
-         * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
-         *         {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
-         */
-        public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
-                KEY_PREFIX + "ike_session_aes_ctr_key_size_int_array";
-
-        /**
-        * List of supported encryption algorithms for IKE session.
-        * Possible values are {@link #ENCRYPTION_ALGORITHM_3DES},
-         * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_8},
-         * {@link #ENCRYPTION_ALGORITHM_AES_GCM_12}, {@link #ENCRYPTION_ALGORITHM_AES_GCM_16}
-        */
-        public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
-                KEY_PREFIX + "supported_ike_session_encryption_algorithms_int_array";
-
-        /**
-         * List of supported integrity algorithms for IKE session
-         * Possible values are {@link #INTEGRITY_ALGORITHM_NONE},
-         * {@link #INTEGRITY_ALGORITHM_HMAC_SHA1_96}, {@link #INTEGRITY_ALGORITHM_AES_XCBC_96},
-         * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_256_128},
-         * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_384_192},
-         * {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
-         */
-        public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY =
-                KEY_PREFIX + "supported_integrity_algorithms_int_array";
-
-        /** Maximum number of retries for tunnel establishment. */
-        public static final String KEY_MAX_RETRIES_INT = KEY_PREFIX + "max_retries_int";
-
-        /** Controls if nat traversal should be enabled. */
-        public static final String KEY_NATT_ENABLED_BOOL = KEY_PREFIX + "natt_enabled_bool";
-
-        /**
-         * Time in seconds after which a NATT keep alive message is sent. If not set or set to <= 0,
-         * default value is 20 seconds.
-         */
-        public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT =
-                KEY_PREFIX + "natt_keep_alive_timer_sec_int";
-
-        /** List of comma separated MCC/MNCs used to create ePDG FQDN as per 3GPP TS 23.003 */
-        public static final String KEY_MCC_MNCS_STRING_ARRAY = KEY_PREFIX + "mcc_mncs_string_array";
-
-        /**
-         * List of supported pseudo random function algorithms for IKE session
-         * Possible values are {@link #PSEUDORANDOM_FUNCTION_HMAC_SHA1},
-         * {@link #PSEUDORANDOM_FUNCTION_AES128_XCBC}
-         */
-        public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = KEY_PREFIX +
-                "supported_prf_algorithms_int_array";
-
-        /**
-         * Time in seconds after which IKE message is retransmitted. If not set or set to <= 0,
-         * default value is 2 seconds.
-         */
-        public static final String KEY_RETRANSMIT_TIMER_SEC_INT =
-                KEY_PREFIX + "retransmit_timer_sec_int";
-
-        /** @hide */
-        @IntDef({
-                AUTHENTICATION_METHOD_EAP_ONLY,
-                AUTHENTICATION_METHOD_CERT
-        })
-        public @interface AuthenticationMethodType {}
-
-        /**
-         * Certificate sent from the server is ignored. Only Extensible Authentication Protocol
-         * (EAP) is used to authenticate the server.
-         * EAP_ONLY_AUTH payload is added to IKE_AUTH request if supported.
-         * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998</a>
-         */
-        public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0;
-        /** Server is authenticated using its certificate. */
-        public static final int AUTHENTICATION_METHOD_CERT = 1;
-
-        /** @hide */
-        @IntDef({
-                EPDG_ADDRESS_STATIC,
-                EPDG_ADDRESS_PLMN,
-                EPDG_ADDRESS_PCO
-        })
-        public @interface EpdgAddressType {}
-
-        /** Use static epdg address. */
-        public static final int EPDG_ADDRESS_STATIC = 0;
-        /** Construct the epdg address using plmn. */
-        public static final int EPDG_ADDRESS_PLMN = 1;
-        /**
-         * Use the epdg address received in protocol configuration options (PCO) from the
-         * network.
-         */
-        public static final int EPDG_ADDRESS_PCO = 2;
-
-        /** @hide */
-        @IntDef({
-                KEY_LEN_UNUSED,
-                KEY_LEN_AES_128,
-                KEY_LEN_AES_192,
-                KEY_LEN_AES_256
-        })
-        public @interface EncrpytionKeyLengthType {}
-
-        public static final int KEY_LEN_UNUSED = SaProposal.KEY_LEN_UNUSED;
-        /** AES Encryption/Ciphering Algorithm key length 128 bits. */
-        public static final int KEY_LEN_AES_128 = SaProposal.KEY_LEN_AES_128;
-        /** AES Encryption/Ciphering Algorithm key length 192 bits. */
-        public static final int KEY_LEN_AES_192 = SaProposal.KEY_LEN_AES_192;
-        /** AES Encryption/Ciphering Algorithm key length 256 bits. */
-        public static final int KEY_LEN_AES_256 = SaProposal.KEY_LEN_AES_256;
-
-        /** @hide */
-        @IntDef({
-                DH_GROUP_NONE,
-                DH_GROUP_1024_BIT_MODP,
-                DH_GROUP_2048_BIT_MODP
-        })
-        public @interface DhGroup {}
-
-        /** None Diffie-Hellman Group. */
-        public static final int DH_GROUP_NONE = SaProposal.DH_GROUP_NONE;
-        /** 1024-bit MODP Diffie-Hellman Group. */
-        public static final int DH_GROUP_1024_BIT_MODP = SaProposal.DH_GROUP_1024_BIT_MODP;
-        /** 2048-bit MODP Diffie-Hellman Group. */
-        public static final int DH_GROUP_2048_BIT_MODP = SaProposal.DH_GROUP_2048_BIT_MODP;
-
-        /** @hide */
-        @IntDef({
-                ENCRYPTION_ALGORITHM_3DES,
-                ENCRYPTION_ALGORITHM_AES_CBC,
-                ENCRYPTION_ALGORITHM_AES_GCM_8,
-                ENCRYPTION_ALGORITHM_AES_GCM_12,
-                ENCRYPTION_ALGORITHM_AES_GCM_16
-        })
-        public @interface EncryptionAlgorithm {}
-
-        /** 3DES Encryption/Ciphering Algorithm. */
-        public static final int ENCRYPTION_ALGORITHM_3DES = SaProposal.ENCRYPTION_ALGORITHM_3DES;
-        /** AES-CBC Encryption/Ciphering Algorithm. */
-        public static final int ENCRYPTION_ALGORITHM_AES_CBC =
-                SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
-
-        /**
-         * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 8-octet ICV
-         * (truncation).
-         */
-        public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 =
-                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
-        /**
-         * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 12-octet ICV
-         * (truncation).
-         */
-        public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 =
-                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
-        /**
-         * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm with 16-octet ICV
-         * (truncation).
-         */
-        public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 =
-                SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
-
-        /** @hide */
-        @IntDef({
-                INTEGRITY_ALGORITHM_NONE,
-                INTEGRITY_ALGORITHM_HMAC_SHA1_96,
-                INTEGRITY_ALGORITHM_AES_XCBC_96,
-                INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
-                INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
-                INTEGRITY_ALGORITHM_HMAC_SHA2_512_256
-        })
-        public @interface IntegrityAlgorithm {}
-
-        /** None Authentication/Integrity Algorithm. */
-        public static final int INTEGRITY_ALGORITHM_NONE = SaProposal.INTEGRITY_ALGORITHM_NONE;
-        /** HMAC-SHA1 Authentication/Integrity Algorithm. */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 =
-                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
-        /** AES-XCBC-96 Authentication/Integrity Algorithm. */
-        public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 =
-                SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
-        /** HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation. */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 =
-                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
-        /** HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation. */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 =
-                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
-        /** HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation. */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 =
-                SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
-
-        /** @hide */
-        @IntDef({
-                PSEUDORANDOM_FUNCTION_HMAC_SHA1,
-                PSEUDORANDOM_FUNCTION_AES128_XCBC
-        })
-        public @interface PseudorandomFunction {}
-
-        /** HMAC-SHA1 Pseudorandom Function. */
-        public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 =
-                SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
-        /** AES128-XCBC Pseudorandom Function. */
-        public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC =
-                SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
-
-        private Iwlan() {}
-
-        private static PersistableBundle getDefaults() {
-            PersistableBundle defaults = new PersistableBundle();
-            defaults.putInt(KEY_IKE_REKEY_SOFT_TIMER_SEC_INT, 3000);
-            defaults.putInt(KEY_IKE_REKEY_HARD_TIMER_SEC_INT, 3600);
-            defaults.putInt(KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT, 3000);
-            defaults.putInt(KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT, 3600);
-            defaults.putInt(KEY_RETRANSMIT_TIMER_SEC_INT, 2);
-            defaults.putInt(KEY_DPD_TIMER_SEC_INT, 120);
-            defaults.putInt(KEY_MAX_RETRIES_INT, 3);
-            defaults.putIntArray(KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY,
-                    new int[]{DH_GROUP_1024_BIT_MODP, DH_GROUP_2048_BIT_MODP});
-            defaults.putIntArray(KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
-                    new int[]{ENCRYPTION_ALGORITHM_3DES, ENCRYPTION_ALGORITHM_AES_CBC});
-            defaults.putIntArray(KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
-                    new int[]{ENCRYPTION_ALGORITHM_3DES, ENCRYPTION_ALGORITHM_AES_CBC});
-            defaults.putIntArray(KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY,
-                    new int[]{INTEGRITY_ALGORITHM_AES_XCBC_96, INTEGRITY_ALGORITHM_HMAC_SHA1_96,
-                            INTEGRITY_ALGORITHM_HMAC_SHA2_256_128});
-            defaults.putIntArray(KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY,
-                    new int[]{PSEUDORANDOM_FUNCTION_HMAC_SHA1, PSEUDORANDOM_FUNCTION_AES128_XCBC});
-            defaults.putBoolean(KEY_NATT_ENABLED_BOOL, true);
-            defaults.putInt(KEY_EPDG_AUTHENTICATION_METHOD_INT, AUTHENTICATION_METHOD_CERT);
-            defaults.putString(KEY_EPDG_STATIC_ADDRESS_STRING, "");
-            defaults.putString(KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING, "");
-            defaults.putInt(KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, 20);
-            defaults.putIntArray(KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
-                    new int[]{KEY_LEN_AES_128, KEY_LEN_AES_256});
-            defaults.putIntArray(KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
-                    new int[]{KEY_LEN_AES_128});
-            defaults.putIntArray(KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
-                    new int[]{KEY_LEN_AES_128, KEY_LEN_AES_256});
-            defaults.putIntArray(KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
-                    new int[]{KEY_LEN_AES_128});
-            defaults.putBoolean(KEY_IKE_FRAGMENTATION_ENABLED_BOOL, false);
-            defaults.putIntArray(KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY, new int[]{EPDG_ADDRESS_PLMN,
-                    EPDG_ADDRESS_STATIC});
-            defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[]{});
-
-            return defaults;
-        }
-    }
-
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -4359,7 +3994,6 @@
         sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
         sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0);
-        sDefaults.putAll(Iwlan.getDefaults());
     }
 
     /**
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 9f26203..5c9fb4e 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -86,7 +86,6 @@
         // TODO(b/146757305): should be unnecessary once
         // sdk_version="module_lib_current"
         "android_system_stubs_current",
-        "framework_mediaprovider_annotation", // for android.annotation.CurrentTimeMillisLong
     ],
     srcs: [
         ":framework-wifi-updatable-sources",
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 7d9bdba..4507cc2 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -900,12 +900,15 @@
     }
 
     /**
-     * Get a unique identifier for a PasspointConfiguration object.
+     * Get a unique identifier for a PasspointConfiguration object. The identifier depends on the
+     * configuration that identify the service provider under the HomeSp subtree, and on the
+     * credential configuration under the Credential subtree.
+     * The method throws an {@link IllegalStateException} if the configuration under HomeSp subtree
+     * or the configuration under Credential subtree are not initialized.
      *
      * @return A unique identifier
-     * @throws IllegalStateException if Credential or HomeSP nodes are not initialized
      */
-    public @NonNull String getUniqueId() throws IllegalStateException {
+    public @NonNull String getUniqueId() {
         if (mCredential == null || mHomeSp == null || TextUtils.isEmpty(mHomeSp.getFqdn())) {
             throw new IllegalStateException("Credential or HomeSP are not initialized");
         }
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 8f6beb1..638efb9 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -426,17 +426,11 @@
      *
      * @throws Exception
      */
-    @Test
+    @Test (expected = IllegalStateException.class)
     public void validateUniqueIdExceptionWithEmptyHomeSp() throws Exception {
         PasspointConfiguration config = PasspointTestUtils.createConfig();
         config.setHomeSp(null);
-        boolean exceptionCaught = false;
-        try {
-            String uniqueId = config.getUniqueId();
-        } catch (IllegalStateException e) {
-            exceptionCaught = true;
-        }
-        assertTrue(exceptionCaught);
+        String uniqueId = config.getUniqueId();
     }
 
     /**
@@ -445,16 +439,10 @@
      *
      * @throws Exception
      */
-    @Test
+    @Test (expected = IllegalStateException.class)
     public void validateUniqueIdExceptionWithEmptyCredential() throws Exception {
         PasspointConfiguration config = PasspointTestUtils.createConfig();
         config.setCredential(null);
-        boolean exceptionCaught = false;
-        try {
-            String uniqueId = config.getUniqueId();
-        } catch (IllegalStateException e) {
-            exceptionCaught = true;
-        }
-        assertTrue(exceptionCaught);
+        String uniqueId = config.getUniqueId();
     }
 }