Merge "Cleanup the resources parsing a bit"
diff --git a/apex/media/framework/java/android/media/MediaTranscodingManager.java b/apex/media/framework/java/android/media/MediaTranscodingManager.java
index 3bfffbcd..aff3204 100644
--- a/apex/media/framework/java/android/media/MediaTranscodingManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodingManager.java
@@ -949,6 +949,8 @@
              *
              * @return the video track format to be used if transcoding should be performed,
              *         and null otherwise.
+             * @throws IllegalArgumentException if the hinted source video format contains invalid
+             *         parameters.
              */
             @Nullable
             public MediaFormat resolveVideoFormat() {
@@ -959,20 +961,19 @@
                 MediaFormat videoTrackFormat = new MediaFormat(mSrcVideoFormatHint);
                 videoTrackFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
 
-                int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH);
-                int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT);
+                int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH, -1);
+                int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT, -1);
                 if (width <= 0 || height <= 0) {
                     throw new IllegalArgumentException(
                             "Source Width and height must be larger than 0");
                 }
 
-                float frameRate = 30.0f; // default to 30fps.
-                if (mSrcVideoFormatHint.containsKey(MediaFormat.KEY_FRAME_RATE)) {
-                    frameRate = mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE);
-                    if (frameRate <= 0) {
-                        throw new IllegalArgumentException(
-                                "frameRate must be larger than 0");
-                    }
+                float frameRate =
+                        mSrcVideoFormatHint.getNumber(MediaFormat.KEY_FRAME_RATE, 30.0)
+                        .floatValue();
+                if (frameRate <= 0) {
+                    throw new IllegalArgumentException(
+                            "frameRate must be larger than 0");
                 }
 
                 int bitrate = getAVCBitrate(width, height, frameRate);
diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
index 002d42d..522e88f 100644
--- a/boot/hiddenapi/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -124,10 +124,8 @@
 Landroid/content/pm/IPackageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/pm/IPackageManager$Stub$Proxy;->checkUidPermission(Ljava/lang/String;I)I
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String;
-Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstallLocation()I
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
-Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
 Landroid/content/pm/IPackageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageManager;
diff --git a/core/api/current.txt b/core/api/current.txt
index 6f58a38..b40a3e5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9037,11 +9037,15 @@
 
   public final class BluetoothClass implements android.os.Parcelable {
     method public int describeContents();
+    method public boolean doesClassMatch(int);
     method public int getDeviceClass();
     method public int getMajorDeviceClass();
     method public boolean hasService(int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothClass> CREATOR;
+    field public static final int PROFILE_A2DP = 1; // 0x1
+    field public static final int PROFILE_HEADSET = 0; // 0x0
+    field public static final int PROFILE_HID = 3; // 0x3
   }
 
   public static class BluetoothClass.Device {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 24ea184..dd1760c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -257,7 +257,7 @@
     field public static final String REQUEST_COMPANION_PROFILE_APP_STREAMING = "android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING";
     field public static final String REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION = "android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION";
     field public static final String REQUEST_COMPANION_SELF_MANAGED = "android.permission.REQUEST_COMPANION_SELF_MANAGED";
-    field public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
+    field @Deprecated public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
     field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
     field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
     field public static final String RESTART_WIFI_SUBSYSTEM = "android.permission.RESTART_WIFI_SUBSYSTEM";
@@ -268,7 +268,7 @@
     field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
     field public static final String ROTATE_SURFACE_FLINGER = "android.permission.ROTATE_SURFACE_FLINGER";
     field public static final String SCHEDULE_PRIORITIZED_ALARM = "android.permission.SCHEDULE_PRIORITIZED_ALARM";
-    field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
+    field @Deprecated public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
     field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
     field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
     field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
@@ -728,6 +728,10 @@
     field public static final String ACTION_DOWNLOAD_COMPLETED = "android.intent.action.DOWNLOAD_COMPLETED";
   }
 
+  public final class GameManager {
+    method @RequiresPermission("android.permission.MANAGE_GAME_MODE") public void setGameMode(@NonNull String, int);
+  }
+
   public abstract class InstantAppResolverService extends android.app.Service {
     ctor public InstantAppResolverService();
     method public final void attachBaseContext(android.content.Context);
@@ -2020,6 +2024,13 @@
     method public void onOobData(int, @NonNull android.bluetooth.OobData);
   }
 
+  public final class BluetoothClass implements android.os.Parcelable {
+    field public static final int PROFILE_A2DP_SINK = 6; // 0x6
+    field public static final int PROFILE_NAP = 5; // 0x5
+    field public static final int PROFILE_OPP = 2; // 0x2
+    field public static final int PROFILE_PANU = 4; // 0x4
+  }
+
   public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
     method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<java.lang.Integer> getAllGroupIds(@Nullable android.os.ParcelUuid);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
@@ -2460,7 +2471,7 @@
     field public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
     field public static final String MUSIC_RECOGNITION_SERVICE = "music_recognition";
     field public static final String NETD_SERVICE = "netd";
-    field public static final String NETWORK_SCORE_SERVICE = "network_score";
+    field @Deprecated public static final String NETWORK_SCORE_SERVICE = "network_score";
     field public static final String OEM_LOCK_SERVICE = "oem_lock";
     field public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
     field public static final String PERMISSION_SERVICE = "permission";
@@ -7696,15 +7707,15 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR;
   }
 
-  public class NetworkKey implements android.os.Parcelable {
-    ctor public NetworkKey(android.net.WifiKey);
-    method @Nullable public static android.net.NetworkKey createFromScanResult(@NonNull android.net.wifi.ScanResult);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR;
-    field public static final int TYPE_WIFI = 1; // 0x1
-    field public final int type;
-    field public final android.net.WifiKey wifiKey;
+  @Deprecated public class NetworkKey implements android.os.Parcelable {
+    ctor @Deprecated public NetworkKey(android.net.WifiKey);
+    method @Deprecated @Nullable public static android.net.NetworkKey createFromScanResult(@NonNull android.net.wifi.ScanResult);
+    method @Deprecated public int describeContents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR;
+    field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
+    field @Deprecated public final int type;
+    field @Deprecated public final android.net.WifiKey wifiKey;
   }
 
   public abstract class NetworkRecommendationProvider {
@@ -7713,31 +7724,31 @@
     method public abstract void onRequestScores(android.net.NetworkKey[]);
   }
 
-  public class NetworkScoreManager {
-    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
-    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
-    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public String getActiveScorerPackage();
-    method @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
-    method @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public boolean requestScores(@NonNull java.util.Collection<android.net.NetworkKey>) throws java.lang.SecurityException;
-    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
-    method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException;
+  @Deprecated public class NetworkScoreManager {
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public String getActiveScorerPackage();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
+    method @Deprecated @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public boolean requestScores(@NonNull java.util.Collection<android.net.NetworkKey>) throws java.lang.SecurityException;
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
+    method @Deprecated @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException;
     field @Deprecated public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
-    field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
-    field public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
-    field public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
+    field @Deprecated public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
+    field @Deprecated public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
+    field @Deprecated public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
     field @Deprecated public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
     field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
-    field public static final String EXTRA_NEW_SCORER = "newScorer";
+    field @Deprecated public static final String EXTRA_NEW_SCORER = "newScorer";
     field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName";
-    field public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1
-    field public static final int SCORE_FILTER_NONE = 0; // 0x0
-    field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2
+    field @Deprecated public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1
+    field @Deprecated public static final int SCORE_FILTER_NONE = 0; // 0x0
+    field @Deprecated public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2
   }
 
-  public abstract static class NetworkScoreManager.NetworkScoreCallback {
-    ctor public NetworkScoreManager.NetworkScoreCallback();
-    method public abstract void onScoresInvalidated();
-    method public abstract void onScoresUpdated(@NonNull java.util.Collection<android.net.ScoredNetwork>);
+  @Deprecated public abstract static class NetworkScoreManager.NetworkScoreCallback {
+    ctor @Deprecated public NetworkScoreManager.NetworkScoreCallback();
+    method @Deprecated public abstract void onScoresInvalidated();
+    method @Deprecated public abstract void onScoresUpdated(@NonNull java.util.Collection<android.net.ScoredNetwork>);
   }
 
   public abstract class NetworkSpecifier {
@@ -7776,35 +7787,35 @@
     ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
   }
 
-  public class RssiCurve implements android.os.Parcelable {
-    ctor public RssiCurve(int, int, byte[]);
-    ctor public RssiCurve(int, int, byte[], int);
-    method public int describeContents();
-    method public byte lookupScore(int);
-    method public byte lookupScore(int, boolean);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.RssiCurve> CREATOR;
-    field public final int activeNetworkRssiBoost;
-    field public final int bucketWidth;
-    field public final byte[] rssiBuckets;
-    field public final int start;
+  @Deprecated public class RssiCurve implements android.os.Parcelable {
+    ctor @Deprecated public RssiCurve(int, int, byte[]);
+    ctor @Deprecated public RssiCurve(int, int, byte[], int);
+    method @Deprecated public int describeContents();
+    method @Deprecated public byte lookupScore(int);
+    method @Deprecated public byte lookupScore(int, boolean);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.RssiCurve> CREATOR;
+    field @Deprecated public final int activeNetworkRssiBoost;
+    field @Deprecated public final int bucketWidth;
+    field @Deprecated public final byte[] rssiBuckets;
+    field @Deprecated public final int start;
   }
 
-  public class ScoredNetwork implements android.os.Parcelable {
-    ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve);
-    ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean);
-    ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, @Nullable android.os.Bundle);
-    method public int calculateBadge(int);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final String ATTRIBUTES_KEY_BADGING_CURVE = "android.net.attributes.key.BADGING_CURVE";
-    field public static final String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
-    field public static final String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET";
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
-    field @Nullable public final android.os.Bundle attributes;
-    field public final boolean meteredHint;
-    field public final android.net.NetworkKey networkKey;
-    field public final android.net.RssiCurve rssiCurve;
+  @Deprecated public class ScoredNetwork implements android.os.Parcelable {
+    ctor @Deprecated public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve);
+    ctor @Deprecated public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean);
+    ctor @Deprecated public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, @Nullable android.os.Bundle);
+    method @Deprecated public int calculateBadge(int);
+    method @Deprecated public int describeContents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final String ATTRIBUTES_KEY_BADGING_CURVE = "android.net.attributes.key.BADGING_CURVE";
+    field @Deprecated public static final String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
+    field @Deprecated public static final String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET";
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
+    field @Deprecated @Nullable public final android.os.Bundle attributes;
+    field @Deprecated public final boolean meteredHint;
+    field @Deprecated public final android.net.NetworkKey networkKey;
+    field @Deprecated public final android.net.RssiCurve rssiCurve;
   }
 
   public class TrafficStats {
@@ -7831,13 +7842,13 @@
     ctor public WebAddress(String) throws android.net.ParseException;
   }
 
-  public class WifiKey implements android.os.Parcelable {
-    ctor public WifiKey(String, String);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.WifiKey> CREATOR;
-    field public final String bssid;
-    field public final String ssid;
+  @Deprecated public class WifiKey implements android.os.Parcelable {
+    ctor @Deprecated public WifiKey(String, String);
+    method @Deprecated public int describeContents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.WifiKey> CREATOR;
+    field @Deprecated public final String bssid;
+    field @Deprecated public final String ssid;
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4b7a9df..c1ab070 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -267,10 +267,6 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
   }
 
-  public final class GameManager {
-    method @RequiresPermission("android.permission.MANAGE_GAME_MODE") public void setGameMode(@NonNull String, int);
-  }
-
   public abstract class HomeVisibilityListener {
     ctor public HomeVisibilityListener();
     method public abstract void onHomeVisibilityChanged(boolean);
@@ -1835,11 +1831,6 @@
     method public int getAudioUsage();
   }
 
-  public static final class VibrationAttributes.Builder {
-    ctor public VibrationAttributes.Builder(@NonNull android.media.AudioAttributes, @NonNull android.os.VibrationEffect);
-    ctor public VibrationAttributes.Builder(@NonNull android.os.VibrationAttributes, @NonNull android.os.VibrationEffect);
-  }
-
   public abstract class VibrationEffect implements android.os.Parcelable {
     method public static android.os.VibrationEffect get(int);
     method public static android.os.VibrationEffect get(int, boolean);
@@ -1856,13 +1847,9 @@
   }
 
   public static final class VibrationEffect.Composed extends android.os.VibrationEffect {
-    method @NonNull public android.os.VibrationEffect.Composed applyEffectStrength(int);
     method public long getDuration();
     method public int getRepeatIndex();
     method @NonNull public java.util.List<android.os.vibrator.VibrationEffectSegment> getSegments();
-    method @NonNull public android.os.VibrationEffect.Composed resolve(int);
-    method @NonNull public android.os.VibrationEffect.Composed scale(float);
-    method public void validate();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Composed> CREATOR;
   }
@@ -2010,72 +1997,47 @@
 package android.os.vibrator {
 
   public final class PrebakedSegment extends android.os.vibrator.VibrationEffectSegment {
-    method @NonNull public android.os.vibrator.PrebakedSegment applyEffectStrength(int);
     method public int describeContents();
     method public long getDuration();
     method public int getEffectId();
     method public int getEffectStrength();
-    method public boolean hasNonZeroAmplitude();
-    method @NonNull public android.os.vibrator.PrebakedSegment resolve(int);
-    method @NonNull public android.os.vibrator.PrebakedSegment scale(float);
     method public boolean shouldFallback();
-    method public void validate();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.PrebakedSegment> CREATOR;
   }
 
   public final class PrimitiveSegment extends android.os.vibrator.VibrationEffectSegment {
-    method @NonNull public android.os.vibrator.PrimitiveSegment applyEffectStrength(int);
     method public int describeContents();
     method public int getDelay();
     method public long getDuration();
     method public int getPrimitiveId();
     method public float getScale();
-    method public boolean hasNonZeroAmplitude();
-    method @NonNull public android.os.vibrator.PrimitiveSegment resolve(int);
-    method @NonNull public android.os.vibrator.PrimitiveSegment scale(float);
-    method public void validate();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.PrimitiveSegment> CREATOR;
   }
 
   public final class RampSegment extends android.os.vibrator.VibrationEffectSegment {
-    method @NonNull public android.os.vibrator.RampSegment applyEffectStrength(int);
     method public int describeContents();
     method public long getDuration();
     method public float getEndAmplitude();
     method public float getEndFrequency();
     method public float getStartAmplitude();
     method public float getStartFrequency();
-    method public boolean hasNonZeroAmplitude();
-    method @NonNull public android.os.vibrator.RampSegment resolve(int);
-    method @NonNull public android.os.vibrator.RampSegment scale(float);
-    method public void validate();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.RampSegment> CREATOR;
   }
 
   public final class StepSegment extends android.os.vibrator.VibrationEffectSegment {
-    method @NonNull public android.os.vibrator.StepSegment applyEffectStrength(int);
     method public int describeContents();
     method public float getAmplitude();
     method public long getDuration();
     method public float getFrequency();
-    method public boolean hasNonZeroAmplitude();
-    method @NonNull public android.os.vibrator.StepSegment resolve(int);
-    method @NonNull public android.os.vibrator.StepSegment scale(float);
-    method public void validate();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.StepSegment> CREATOR;
   }
 
   public abstract class VibrationEffectSegment implements android.os.Parcelable {
-    method @NonNull public abstract <T extends android.os.vibrator.VibrationEffectSegment> T applyEffectStrength(int);
     method public abstract long getDuration();
-    method public abstract boolean hasNonZeroAmplitude();
-    method @NonNull public abstract <T extends android.os.vibrator.VibrationEffectSegment> T resolve(int);
-    method @NonNull public abstract <T extends android.os.vibrator.VibrationEffectSegment> T scale(float);
-    method public abstract void validate();
     field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.VibrationEffectSegment> CREATOR;
   }
 
@@ -2195,7 +2157,7 @@
     field public static final String USER_PREFERRED_REFRESH_RATE = "user_preferred_refresh_rate";
     field public static final String USER_PREFERRED_RESOLUTION_HEIGHT = "user_preferred_resolution_height";
     field public static final String USER_PREFERRED_RESOLUTION_WIDTH = "user_preferred_resolution_width";
-    field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
+    field @Deprecated public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
   }
 
   public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index b324fb6..78759db 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -21,8 +21,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.annotation.UserHandleAware;
 import android.content.Context;
 import android.os.Handler;
@@ -125,7 +125,7 @@
      *
      * @hide
      */
-    @TestApi
+    @SystemApi
     @UserHandleAware
     @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
     public void setGameMode(@NonNull String packageName, @GameMode int gameMode) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 0476307..089c269 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -200,6 +200,8 @@
 import android.scheduling.SchedulingFrameworkInitializer;
 import android.security.FileIntegrityManager;
 import android.security.IFileIntegrityService;
+import android.security.attestationverification.AttestationVerificationManager;
+import android.security.attestationverification.IAttestationVerificationManagerService;
 import android.service.oemlock.IOemLockService;
 import android.service.oemlock.OemLockManager;
 import android.service.persistentdata.IPersistentDataBlockService;
@@ -1425,6 +1427,19 @@
                         return new FileIntegrityManager(ctx.getOuterContext(),
                                 IFileIntegrityService.Stub.asInterface(b));
                     }});
+
+        registerService(Context.ATTESTATION_VERIFICATION_SERVICE,
+                AttestationVerificationManager.class,
+                new CachedServiceFetcher<AttestationVerificationManager>() {
+                    @Override
+                    public AttestationVerificationManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.ATTESTATION_VERIFICATION_SERVICE);
+                        return new AttestationVerificationManager(ctx.getOuterContext(),
+                                IAttestationVerificationManagerService.Stub.asInterface(b));
+                    }});
+
         //CHECKSTYLE:ON IndentationCheck
         registerService(Context.APP_INTEGRITY_SERVICE, AppIntegrityManager.class,
                 new CachedServiceFetcher<AppIntegrityManager>() {
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 7fe18a0..69525b5 100755
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -327,21 +328,26 @@
         return Arrays.copyOfRange(bytes, 1, bytes.length);
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
     public static final int PROFILE_HEADSET = 0;
-    /** @hide */
-    @UnsupportedAppUsage
+
     public static final int PROFILE_A2DP = 1;
+
     /** @hide */
+    @SystemApi
     public static final int PROFILE_OPP = 2;
-    /** @hide */
+
     public static final int PROFILE_HID = 3;
+
     /** @hide */
+    @SystemApi
     public static final int PROFILE_PANU = 4;
+
     /** @hide */
+    @SystemApi
     public static final int PROFILE_NAP = 5;
+
     /** @hide */
+    @SystemApi
     public static final int PROFILE_A2DP_SINK = 6;
 
     /**
@@ -350,11 +356,9 @@
      * given class bits might support specified profile. It is not accurate for all
      * devices. It tries to err on the side of false positives.
      *
-     * @param profile The profile to be checked
-     * @return True if this device might support specified profile.
-     * @hide
+     * @param profile the profile to be checked
+     * @return whether this device supports specified profile
      */
-    @UnsupportedAppUsage
     public boolean doesClassMatch(int profile) {
         if (profile == PROFILE_A2DP) {
             if (hasService(Service.RENDER)) {
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index f70e662..3f02aa2 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -118,7 +118,7 @@
 
     /** @hide */
     public @Nullable String getDeviceMacAddressAsString() {
-        return mDeviceMacAddress != null ? mDeviceMacAddress.toString() : null;
+        return mDeviceMacAddress != null ? mDeviceMacAddress.toString().toUpperCase() : null;
     }
 
     /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 05e2e87..2b75022 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3842,6 +3842,7 @@
             UWB_SERVICE,
             MEDIA_METRICS_SERVICE,
             SUPPLEMENTAL_PROCESS_SERVICE,
+            //@hide: ATTESTATION_VERIFICATION_SERVICE,
             //@hide: SAFETY_CENTER_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -5355,9 +5356,12 @@
      * {@link android.net.NetworkScoreManager} for managing network scoring.
      * @see #getSystemService(String)
      * @see android.net.NetworkScoreManager
+     * @deprecated see https://developer.android.com/guide/topics/connectivity/wifi-suggest for
+     * alternative API to propose WiFi networks.
      * @hide
      */
     @SystemApi
+    @Deprecated
     public static final String NETWORK_SCORE_SERVICE = "network_score";
 
     /**
@@ -5740,6 +5744,15 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.security.attestationverification.AttestationVerificationManager}.
+     * @see #getSystemService(String)
+     * @see android.security.attestationverification.AttestationVerificationManager
+     * @hide
+     */
+    public static final String ATTESTATION_VERIFICATION_SERVICE = "attestation_verification";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.security.FileIntegrityManager}.
      * @see #getSystemService(String)
      * @see android.security.FileIntegrityManager
@@ -5883,6 +5896,16 @@
     public static final String SAFETY_CENTER_SERVICE = "safety_center";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.nearby.NearbyManager} to discover nearby devices.
+     *
+     * @see #getSystemService(String)
+     * @see android.nearby.NearbyManager
+     * @hide
+     */
+    public static final String NEARBY_SERVICE = "nearby";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 516156d..1c82b38 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -69,41 +69,34 @@
     void checkPackageStartable(String packageName, int userId);
     @UnsupportedAppUsage(trackingBug = 171933273)
     boolean isPackageAvailable(String packageName, int userId);
-    @UnsupportedAppUsage
-    PackageInfo getPackageInfo(String packageName, int flags, int userId);
+    PackageInfo getPackageInfo(String packageName, long flags, int userId);
     PackageInfo getPackageInfoVersioned(in VersionedPackage versionedPackage,
-            int flags, int userId);
-    @UnsupportedAppUsage
-    int getPackageUid(String packageName, int flags, int userId);
-    int[] getPackageGids(String packageName, int flags, int userId);
+            long flags, int userId);
+    int getPackageUid(String packageName, long flags, int userId);
+    int[] getPackageGids(String packageName, long flags, int userId);
 
     @UnsupportedAppUsage
     String[] currentToCanonicalPackageNames(in String[] names);
     @UnsupportedAppUsage
     String[] canonicalToCurrentPackageNames(in String[] names);
 
-    @UnsupportedAppUsage
-    ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
+    ApplicationInfo getApplicationInfo(String packageName, long flags, int userId);
 
     /**
      * @return the target SDK for the given package name, or -1 if it cannot be retrieved
      */
     int getTargetSdkVersion(String packageName);
 
-    @UnsupportedAppUsage
-    ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId);
+    ActivityInfo getActivityInfo(in ComponentName className, long flags, int userId);
 
     boolean activitySupportsIntent(in ComponentName className, in Intent intent,
             String resolvedType);
 
-    @UnsupportedAppUsage
-    ActivityInfo getReceiverInfo(in ComponentName className, int flags, int userId);
+    ActivityInfo getReceiverInfo(in ComponentName className, long flags, int userId);
 
-    @UnsupportedAppUsage
-    ServiceInfo getServiceInfo(in ComponentName className, int flags, int userId);
+    ServiceInfo getServiceInfo(in ComponentName className, long flags, int userId);
 
-    @UnsupportedAppUsage
-    ProviderInfo getProviderInfo(in ComponentName className, int flags, int userId);
+    ProviderInfo getProviderInfo(in ComponentName className, long flags, int userId);
 
     boolean isProtectedBroadcast(String actionName);
 
@@ -133,33 +126,31 @@
     @UnsupportedAppUsage
     boolean isUidPrivileged(int uid);
 
-    @UnsupportedAppUsage
-    ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
+    ResolveInfo resolveIntent(in Intent intent, String resolvedType, long flags, int userId);
 
     ResolveInfo findPersistentPreferredActivity(in Intent intent, int userId);
 
     boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
 
-    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     ParceledListSlice queryIntentActivities(in Intent intent,
-            String resolvedType, int flags, int userId);
+            String resolvedType, long flags, int userId);
 
     ParceledListSlice queryIntentActivityOptions(
             in ComponentName caller, in Intent[] specifics,
             in String[] specificTypes, in Intent intent,
-            String resolvedType, int flags, int userId);
+            String resolvedType, long flags, int userId);
 
     ParceledListSlice queryIntentReceivers(in Intent intent,
-            String resolvedType, int flags, int userId);
+            String resolvedType, long flags, int userId);
 
     ResolveInfo resolveService(in Intent intent,
-            String resolvedType, int flags, int userId);
+            String resolvedType, long flags, int userId);
 
     ParceledListSlice queryIntentServices(in Intent intent,
-            String resolvedType, int flags, int userId);
+            String resolvedType, long flags, int userId);
 
     ParceledListSlice queryIntentContentProviders(in Intent intent,
-            String resolvedType, int flags, int userId);
+            String resolvedType, long flags, int userId);
 
     /**
      * This implements getInstalledPackages via a "last returned row"
@@ -167,8 +158,7 @@
      * limit that kicks in when flags are included that bloat up the data
      * returned.
      */
-    @UnsupportedAppUsage
-    ParceledListSlice getInstalledPackages(int flags, in int userId);
+    ParceledListSlice getInstalledPackages(long flags, in int userId);
 
     /**
      * This implements getPackagesHoldingPermissions via a "last returned row"
@@ -177,7 +167,7 @@
      * returned.
      */
     ParceledListSlice getPackagesHoldingPermissions(in String[] permissions,
-            int flags, int userId);
+            long flags, int userId);
 
     /**
      * This implements getInstalledApplications via a "last returned row"
@@ -185,18 +175,17 @@
      * limit that kicks in when flags are included that bloat up the data
      * returned.
      */
-    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
-    ParceledListSlice getInstalledApplications(int flags, int userId);
+    ParceledListSlice getInstalledApplications(long flags, int userId);
 
     /**
      * Retrieve all applications that are marked as persistent.
      *
-     * @return A List&lt;applicationInfo> containing one entry for each persistent
+     * @return A List<ApplicationInfo> containing one entry for each persistent
      *         application.
      */
     ParceledListSlice getPersistentApplications(int flags);
 
-    ProviderInfo resolveContentProvider(String name, int flags, int userId);
+    ProviderInfo resolveContentProvider(String name, long flags, int userId);
 
     /**
      * Retrieve sync information for all content providers.
@@ -211,7 +200,7 @@
             inout List<ProviderInfo> outInfo);
 
     ParceledListSlice queryContentProviders(
-            String processName, int uid, int flags, String metaDataKey);
+            String processName, int uid, long flags, String metaDataKey);
 
     @UnsupportedAppUsage
     InstrumentationInfo getInstrumentationInfo(
@@ -690,9 +679,9 @@
 
     int getInstallReason(String packageName, int userId);
 
-    ParceledListSlice getSharedLibraries(in String packageName, int flags, int userId);
+    ParceledListSlice getSharedLibraries(in String packageName, long flags, int userId);
 
-    ParceledListSlice getDeclaredSharedLibraries(in String packageName, int flags, int userId);
+    ParceledListSlice getDeclaredSharedLibraries(in String packageName, long flags, int userId);
 
     boolean canRequestPackageInstalls(String packageName, int userId);
 
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index cc4782a..aa57806 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -10,6 +10,9 @@
       "path": "frameworks/base/services/tests/PackageManagerComponentOverrideTests"
     },
     {
+      "path": "frameworks/base/services/tests/servicestests/src/com/android/server/pm"
+    },
+    {
       "path": "cts/tests/tests/packageinstaller"
     },
     {
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index ef124c7..b11b38a 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -76,7 +76,7 @@
 
     @Nullable
     public static PackageInfo generate(ParsingPackageRead pkg, int[] gids,
-            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            @PackageManager.PackageInfoFlags long flags, long firstInstallTime, long lastUpdateTime,
             Set<String> grantedPermissions, FrameworkPackageUserState state, int userId) {
         return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions,
                 state, userId, null);
@@ -90,7 +90,7 @@
 
     @Nullable
     private static PackageInfo generateWithComponents(ParsingPackageRead pkg, int[] gids,
-            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            @PackageManager.PackageInfoFlags long flags, long firstInstallTime, long lastUpdateTime,
             Set<String> grantedPermissions, FrameworkPackageUserState state, int userId,
             @Nullable ApexInfo apexInfo) {
         ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
@@ -190,7 +190,7 @@
 
     @Nullable
     public static PackageInfo generateWithoutComponents(ParsingPackageRead pkg, int[] gids,
-            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            @PackageManager.PackageInfoFlags long flags, long firstInstallTime, long lastUpdateTime,
             Set<String> grantedPermissions, FrameworkPackageUserState state, int userId,
             @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
         if (!checkUseInstalled(pkg, state, flags)) {
@@ -210,9 +210,9 @@
      */
     @NonNull
     public static PackageInfo generateWithoutComponentsUnchecked(ParsingPackageRead pkg, int[] gids,
-            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
-            Set<String> grantedPermissions, FrameworkPackageUserState state, int userId,
-            @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
+            @PackageManager.PackageInfoFlags long flags, long firstInstallTime,
+            long lastUpdateTime, Set<String> grantedPermissions, FrameworkPackageUserState state,
+            int userId, @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
         PackageInfo pi = new PackageInfo();
         pi.packageName = pkg.getPackageName();
         pi.splitNames = pkg.getSplitNames();
@@ -365,7 +365,8 @@
 
     @Nullable
     public static ApplicationInfo generateApplicationInfo(ParsingPackageRead pkg,
-            @PackageManager.ApplicationInfoFlags int flags, FrameworkPackageUserState state, int userId) {
+            @PackageManager.ApplicationInfoFlags long flags, FrameworkPackageUserState state,
+            int userId) {
         if (pkg == null) {
             return null;
         }
@@ -392,8 +393,8 @@
      */
     @NonNull
     public static ApplicationInfo generateApplicationInfoUnchecked(@NonNull ParsingPackageRead pkg,
-            @PackageManager.ApplicationInfoFlags int flags, @NonNull FrameworkPackageUserState state,
-            int userId, boolean assignUserFields) {
+            @PackageManager.ApplicationInfoFlags long flags,
+            @NonNull FrameworkPackageUserState state, int userId, boolean assignUserFields) {
         // Make shallow copy so we can store the metadata/libraries safely
         ApplicationInfo ai = ((ParsingPackageHidden) pkg).toAppInfoWithoutState();
 
@@ -406,7 +407,7 @@
         return ai;
     }
 
-    private static void updateApplicationInfo(ApplicationInfo ai, int flags,
+    private static void updateApplicationInfo(ApplicationInfo ai, long flags,
             FrameworkPackageUserState state) {
         if ((flags & PackageManager.GET_META_DATA) == 0) {
             ai.metaData = null;
@@ -452,8 +453,8 @@
 
     @Nullable
     public static ApplicationInfo generateDelegateApplicationInfo(@Nullable ApplicationInfo ai,
-            @PackageManager.ApplicationInfoFlags int flags, @NonNull FrameworkPackageUserState state,
-            int userId) {
+            @PackageManager.ApplicationInfoFlags long flags,
+            @NonNull FrameworkPackageUserState state, int userId) {
         if (ai == null || !checkUseInstalledOrHidden(flags, state, ai)) {
             return null;
         }
@@ -469,7 +470,7 @@
 
     @Nullable
     public static ActivityInfo generateDelegateActivityInfo(@Nullable ActivityInfo a,
-            @PackageManager.ComponentInfoFlags int flags, @NonNull FrameworkPackageUserState state,
+            @PackageManager.ComponentInfoFlags long flags, @NonNull FrameworkPackageUserState state,
             int userId) {
         if (a == null || !checkUseInstalledOrHidden(flags, state, a.applicationInfo)) {
             return null;
@@ -484,7 +485,7 @@
 
     @Nullable
     public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
-            @PackageManager.ComponentInfoFlags int flags, FrameworkPackageUserState state,
+            @PackageManager.ComponentInfoFlags long flags, FrameworkPackageUserState state,
             @Nullable ApplicationInfo applicationInfo, int userId) {
         if (a == null) return null;
         if (!checkUseInstalled(pkg, state, flags)) {
@@ -504,12 +505,12 @@
      * This bypasses critical checks that are necessary for usage with data passed outside of system
      * server.
      * <p>
-     * Prefer {@link #generateActivityInfo(ParsingPackageRead, ParsedActivity, int,
+     * Prefer {@link #generateActivityInfo(ParsingPackageRead, ParsedActivity, long,
      * FrameworkPackageUserState, ApplicationInfo, int)}.
      */
     @NonNull
     public static ActivityInfo generateActivityInfoUnchecked(@NonNull ParsedActivity a,
-            @PackageManager.ComponentInfoFlags int flags,
+            @PackageManager.ComponentInfoFlags long flags,
             @NonNull ApplicationInfo applicationInfo) {
         // Make shallow copies so we can store the metadata safely
         ActivityInfo ai = new ActivityInfo();
@@ -550,13 +551,14 @@
 
     @Nullable
     public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
-            @PackageManager.ComponentInfoFlags int flags, FrameworkPackageUserState state, int userId) {
+            @PackageManager.ComponentInfoFlags long flags, FrameworkPackageUserState state,
+            int userId) {
         return generateActivityInfo(pkg, a, flags, state, null, userId);
     }
 
     @Nullable
     public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
-            @PackageManager.ComponentInfoFlags int flags, FrameworkPackageUserState state,
+            @PackageManager.ComponentInfoFlags long flags, FrameworkPackageUserState state,
             @Nullable ApplicationInfo applicationInfo, int userId) {
         if (s == null) return null;
         if (!checkUseInstalled(pkg, state, flags)) {
@@ -576,12 +578,12 @@
      * This bypasses critical checks that are necessary for usage with data passed outside of system
      * server.
      * <p>
-     * Prefer {@link #generateServiceInfo(ParsingPackageRead, ParsedService, int, FrameworkPackageUserState,
-     * ApplicationInfo, int)}.
+     * Prefer {@link #generateServiceInfo(ParsingPackageRead, ParsedService, long,
+     * FrameworkPackageUserState, ApplicationInfo, int)}.
      */
     @NonNull
     public static ServiceInfo generateServiceInfoUnchecked(@NonNull ParsedService s,
-            @PackageManager.ComponentInfoFlags int flags,
+            @PackageManager.ComponentInfoFlags long flags,
             @NonNull ApplicationInfo applicationInfo) {
         // Make shallow copies so we can store the metadata safely
         ServiceInfo si = new ServiceInfo();
@@ -600,13 +602,14 @@
 
     @Nullable
     public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
-            @PackageManager.ComponentInfoFlags int flags, FrameworkPackageUserState state, int userId) {
+            @PackageManager.ComponentInfoFlags long flags, FrameworkPackageUserState state,
+            int userId) {
         return generateServiceInfo(pkg, s, flags, state, null, userId);
     }
 
     @Nullable
     public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
-            @PackageManager.ComponentInfoFlags int flags, FrameworkPackageUserState state,
+            @PackageManager.ComponentInfoFlags long flags, FrameworkPackageUserState state,
             @Nullable ApplicationInfo applicationInfo, int userId) {
         if (p == null) return null;
         if (!checkUseInstalled(pkg, state, flags)) {
@@ -626,12 +629,12 @@
      * This bypasses critical checks that are necessary for usage with data passed outside of system
      * server.
      * <p>
-     * Prefer {@link #generateProviderInfo(ParsingPackageRead, ParsedProvider, int,
+     * Prefer {@link #generateProviderInfo(ParsingPackageRead, ParsedProvider, long,
      * FrameworkPackageUserState, ApplicationInfo, int)}.
      */
     @NonNull
     public static ProviderInfo generateProviderInfoUnchecked(@NonNull ParsedProvider p,
-            @PackageManager.ComponentInfoFlags int flags,
+            @PackageManager.ComponentInfoFlags long flags,
             @NonNull ApplicationInfo applicationInfo) {
         // Make shallow copies so we can store the metadata safely
         ProviderInfo pi = new ProviderInfo();
@@ -661,17 +664,18 @@
 
     @Nullable
     public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
-            @PackageManager.ComponentInfoFlags int flags, FrameworkPackageUserState state, int userId) {
+            @PackageManager.ComponentInfoFlags long flags, FrameworkPackageUserState state,
+            int userId) {
         return generateProviderInfo(pkg, p, flags, state, null, userId);
     }
 
     /**
-     * @param assignUserFields see {@link #generateApplicationInfoUnchecked(ParsingPackageRead, int,
-     *                         FrameworkPackageUserState, int, boolean)}
+     * @param assignUserFields see {@link #generateApplicationInfoUnchecked(ParsingPackageRead,
+     * long, FrameworkPackageUserState, int, boolean)}
      */
     @Nullable
     public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
-            ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags int flags, int userId,
+            ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags long flags, int userId,
             boolean assignUserFields) {
         if (i == null) return null;
 
@@ -702,7 +706,7 @@
 
     @Nullable
     public static PermissionInfo generatePermissionInfo(ParsedPermission p,
-            @PackageManager.ComponentInfoFlags int flags) {
+            @PackageManager.ComponentInfoFlags long flags) {
         if (p == null) return null;
 
         PermissionInfo pi = new PermissionInfo(p.getBackgroundPermission());
@@ -725,7 +729,7 @@
 
     @Nullable
     public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
-            @PackageManager.ComponentInfoFlags int flags) {
+            @PackageManager.ComponentInfoFlags long flags) {
         if (pg == null) return null;
 
         PermissionGroupInfo pgi = new PermissionGroupInfo(
@@ -753,8 +757,8 @@
         return new Attribution(pa.getTag(), pa.getLabel());
     }
 
-    private static boolean checkUseInstalledOrHidden(int flags, @NonNull FrameworkPackageUserState state,
-            @Nullable ApplicationInfo appInfo) {
+    private static boolean checkUseInstalledOrHidden(long flags,
+            @NonNull FrameworkPackageUserState state, @Nullable ApplicationInfo appInfo) {
         // Returns false if the package is hidden system app until installed.
         if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
                 && !state.isInstalled()
@@ -882,8 +886,8 @@
         return privateFlagsExt;
     }
 
-    private static boolean checkUseInstalled(ParsingPackageRead pkg, FrameworkPackageUserState state,
-            @PackageManager.PackageInfoFlags int flags) {
+    private static boolean checkUseInstalled(ParsingPackageRead pkg,
+            FrameworkPackageUserState state, @PackageManager.PackageInfoFlags long flags) {
         // If available for the target user
         return PackageUserStateUtils.isAvailable(state, flags);
     }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index f07f382..d5957a2 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -334,7 +334,7 @@
     @DataClass.ParcelWith(ForInternedString.class)
     private String backupAgentName;
     private int banner;
-    private int category;
+    private int category = ApplicationInfo.CATEGORY_UNDEFINED;
     @Nullable
     @DataClass.ParcelWith(ForInternedString.class)
     private String classLoaderName;
diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
index 1ac9739..0334601 100644
--- a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
@@ -170,13 +170,13 @@
     }
 
     public static boolean isMatch(FrameworkPackageUserState state, boolean isSystem,
-            boolean isPackageEnabled, ParsedMainComponent component, int flags) {
+            boolean isPackageEnabled, ParsedMainComponent component, long flags) {
         return PackageUserStateUtils.isMatch(state, isSystem, isPackageEnabled,
                 component.isEnabled(), component.isDirectBootAware(), component.getName(), flags);
     }
 
     public static boolean isEnabled(FrameworkPackageUserState state, boolean isPackageEnabled,
-            ParsedMainComponent parsedComponent, int flags) {
+            ParsedMainComponent parsedComponent, long flags) {
         return PackageUserStateUtils.isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
                 parsedComponent.getName(), flags);
     }
diff --git a/core/java/android/content/pm/pkg/PackageUserStateUtils.java b/core/java/android/content/pm/pkg/PackageUserStateUtils.java
index 9a800b0..468bff1 100644
--- a/core/java/android/content/pm/pkg/PackageUserStateUtils.java
+++ b/core/java/android/content/pm/pkg/PackageUserStateUtils.java
@@ -34,15 +34,15 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "PackageUserStateUtils";
 
-    public static boolean isMatch(@NonNull FrameworkPackageUserState state, ComponentInfo componentInfo,
-            int flags) {
+    public static boolean isMatch(@NonNull FrameworkPackageUserState state,
+            ComponentInfo componentInfo, long flags) {
         return isMatch(state, componentInfo.applicationInfo.isSystemApp(),
                 componentInfo.applicationInfo.enabled, componentInfo.enabled,
                 componentInfo.directBootAware, componentInfo.name, flags);
     }
 
     public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
-            boolean isPackageEnabled, ParsedMainComponent component, int flags) {
+            boolean isPackageEnabled, ParsedMainComponent component, long flags) {
         return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(),
                 component.isDirectBootAware(), component.getName(), flags);
     }
@@ -58,7 +58,7 @@
      */
     public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
             boolean isPackageEnabled, boolean isComponentEnabled,
-            boolean isComponentDirectBootAware, String componentName, int flags) {
+            boolean isComponentDirectBootAware, String componentName, long flags) {
         final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
         if (!isAvailable(state, flags) && !(isSystem && matchUninstalled)) {
             return reportIfDebug(false, flags);
@@ -81,7 +81,7 @@
         return reportIfDebug(matchesUnaware || matchesAware, flags);
     }
 
-    public static boolean isAvailable(@NonNull FrameworkPackageUserState state, int flags) {
+    public static boolean isAvailable(@NonNull FrameworkPackageUserState state, long flags) {
         // True if it is installed for this user and it is not hidden. If it is hidden,
         // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
         final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
@@ -91,7 +91,7 @@
                 && (!state.isHidden() || matchUninstalled));
     }
 
-    public static boolean reportIfDebug(boolean result, int flags) {
+    public static boolean reportIfDebug(boolean result, long flags) {
         if (DEBUG && !result) {
             Slog.i(TAG, "No match!; flags: "
                     + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
@@ -101,13 +101,13 @@
     }
 
     public static boolean isEnabled(@NonNull FrameworkPackageUserState state, ComponentInfo componentInfo,
-            int flags) {
+            long flags) {
         return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled,
                 componentInfo.name, flags);
     }
 
     public static boolean isEnabled(@NonNull FrameworkPackageUserState state, boolean isPackageEnabled,
-            ParsedMainComponent parsedComponent, int flags) {
+            ParsedMainComponent parsedComponent, long flags) {
         return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
                 parsedComponent.getName(), flags);
     }
@@ -115,8 +115,9 @@
     /**
      * Test if the given component is considered enabled.
      */
-    public static boolean isEnabled(@NonNull FrameworkPackageUserState state, boolean isPackageEnabled,
-            boolean isComponentEnabled, String componentName, int flags) {
+    public static boolean isEnabled(@NonNull FrameworkPackageUserState state,
+            boolean isPackageEnabled, boolean isComponentEnabled, String componentName,
+            long flags) {
         if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
             return true;
         }
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 83e1061..2985c75 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.graphics.Point;
 import android.hardware.SensorManager;
+import android.media.projection.IMediaProjection;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.PowerManager;
@@ -380,6 +381,31 @@
     public abstract void onEarlyInteractivityChange(boolean interactive);
 
     /**
+     * A special API for creates a virtual display with a DisplayPolicyController in system_server.
+     * <p>
+     * If this method is called without original calling uid, the caller must enforce the
+     * corresponding permissions according to the flags.
+     *   {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
+     *   {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT}
+     *   {@link android.Manifest.permission#ADD_TRUSTED_DISPLAY}
+     *   {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW}
+     * </p>
+     *
+     * @param virtualDisplayConfig The arguments for the virtual display configuration. See
+     *                             {@link VirtualDisplayConfig} for using it.
+     * @param callback Callback to call when the virtual display's state changes, or null if none.
+     * @param projection MediaProjection token.
+     * @param packageName The package name of the app.
+     * @param controller The DisplayWindowPolicyControl that can control what contents are
+     *                   allowed to be displayed.
+     * @return The newly created virtual display id , or {@link Display#INVALID_DISPLAY} if the
+     * virtual display cannot be created.
+     */
+    public abstract int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
+            IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
+            DisplayWindowPolicyController controller);
+
+    /**
      * Get {@link DisplayWindowPolicyController} associated to the {@link DisplayInfo#displayId}
      *
      * @param displayId The id of the display.
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index e5d8620..6f0c944 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1016,9 +1016,8 @@
     }
 
     /**
-     * Queries the framework about whether any physical keys exist on the
-     * any keyboard attached to the device that are capable of producing the given
-     * array of key codes.
+     * Queries the framework about whether any physical keys exist on any currently attached input
+     * devices that are capable of producing the given array of key codes.
      *
      * @param keyCodes The array of key codes to query.
      * @return A new array of the same size as the key codes array whose elements
@@ -1032,11 +1031,10 @@
     }
 
     /**
-     * Queries the framework about whether any physical keys exist on the
-     * any keyboard attached to the device that are capable of producing the given
-     * array of key codes.
+     * Queries the framework about whether any physical keys exist on the specified input device
+     * that are capable of producing the given array of key codes.
      *
-     * @param id The id of the device to query.
+     * @param id The id of the input device to query or -1 to consult all devices.
      * @param keyCodes The array of key codes to query.
      * @return A new array of the same size as the key codes array whose elements are set to true
      * if the given device could produce the corresponding key code at the same index in the key
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index 5cd4eb5..5e0e1b7 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -35,8 +35,10 @@
 /**
  * Information which identifies a specific network.
  *
+ * @deprecated as part of the {@link NetworkScoreManager} deprecation.
  * @hide
  */
+@Deprecated
 @SystemApi
 // NOTE: Ideally, we would abstract away the details of what identifies a network of a specific
 // type, so that all networks appear the same and can be scored without concern to the network type
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 0ba2663..7b8b5c0 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -51,9 +51,13 @@
  *     permission.
  * </ul>
  *
+ * @deprecated No longer functional on {@link android.os.Build.VERSION_CODES#TIRAMISU} and above.
+ * See https://developer.android.com/guide/topics/connectivity/wifi-suggest for
+ * alternative APIs to suggest/configure Wi-Fi networks.
  * @hide
  */
 @SystemApi
+@Deprecated
 @SystemService(Context.NETWORK_SCORE_SERVICE)
 public class NetworkScoreManager {
     private static final String TAG = "NetworkScoreManager";
@@ -245,7 +249,7 @@
      *                           or {@link permission#REQUEST_NETWORK_SCORES} permissions.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
-                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
+            android.Manifest.permission.REQUEST_NETWORK_SCORES})
     public String getActiveScorerPackage() {
         try {
             return mService.getActiveScorerPackage();
@@ -322,7 +326,7 @@
      *                           hold the {@link permission#REQUEST_NETWORK_SCORES} permission.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
-                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
+            android.Manifest.permission.REQUEST_NETWORK_SCORES})
     public boolean clearScores() throws SecurityException {
         try {
             return mService.clearScores();
@@ -344,7 +348,7 @@
      */
     @SystemApi
     @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
-                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
+            android.Manifest.permission.REQUEST_NETWORK_SCORES})
     public boolean setActiveScorer(String packageName) throws SecurityException {
         try {
             return mService.setActiveScorer(packageName);
@@ -362,7 +366,7 @@
      *                           hold the {@link permission#REQUEST_NETWORK_SCORES} permission.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
-                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
+            android.Manifest.permission.REQUEST_NETWORK_SCORES})
     public void disableScoring() throws SecurityException {
         try {
             mService.disableScoring();
diff --git a/core/java/android/net/RssiCurve.java b/core/java/android/net/RssiCurve.java
index 668e966..02cafb5 100644
--- a/core/java/android/net/RssiCurve.java
+++ b/core/java/android/net/RssiCurve.java
@@ -50,8 +50,10 @@
  * the system.
  *
  * @see ScoredNetwork
+ * @deprecated as part of the {@link NetworkScoreManager} deprecation.
  * @hide
  */
+@Deprecated
 @SystemApi
 public class RssiCurve implements Parcelable {
     private static final int DEFAULT_ACTIVE_NETWORK_RSSI_BOOST = 25;
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index 64b3bf1..a46bdd9a 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -29,8 +29,10 @@
 /**
  * A network identifier along with a score for the quality of that network.
  *
+ * @deprecated as part of the {@link NetworkScoreManager} deprecation.
  * @hide
  */
+@Deprecated
 @SystemApi
 public class ScoredNetwork implements Parcelable {
 
diff --git a/core/java/android/net/WifiKey.java b/core/java/android/net/WifiKey.java
index bc9d8c5..2e4ea89 100644
--- a/core/java/android/net/WifiKey.java
+++ b/core/java/android/net/WifiKey.java
@@ -29,8 +29,10 @@
  * Information identifying a Wi-Fi network.
  * @see NetworkKey
  *
+ * @deprecated as part of the {@link NetworkScore} deprecation.
  * @hide
  */
+@Deprecated
 @SystemApi
 public class WifiKey implements Parcelable {
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a4a76a8..53484d2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -7354,9 +7354,11 @@
                         pw.print(getHistoryTagPoolUid(i));
                         pw.print(",\"");
                         String str = getHistoryTagPoolString(i);
-                        str = str.replace("\\", "\\\\");
-                        str = str.replace("\"", "\\\"");
-                        pw.print(str);
+                        if (str != null) {
+                            str = str.replace("\\", "\\\\");
+                            str = str.replace("\"", "\\\"");
+                            pw.print(str);
+                        }
                         pw.print("\"");
                         pw.println();
                     }
diff --git a/core/java/android/os/CombinedVibration.java b/core/java/android/os/CombinedVibration.java
index aff55af..5f2c113 100644
--- a/core/java/android/os/CombinedVibration.java
+++ b/core/java/android/os/CombinedVibration.java
@@ -110,6 +110,20 @@
     @TestApi
     public abstract long getDuration();
 
+    /**
+     * Returns true if this effect could represent a touch haptic feedback.
+     *
+     * <p>It is strongly recommended that an instance of {@link VibrationAttributes} is specified
+     * for each vibration, with the correct usage. When a vibration is played with usage UNKNOWN,
+     * then this method will be used to classify the most common use case and make sure they are
+     * covered by the user settings for "Touch feedback".
+     *
+     * @hide
+     */
+    public boolean isHapticFeedbackCandidate() {
+        return false;
+    }
+
     /** @hide */
     public abstract void validate();
 
@@ -314,6 +328,12 @@
 
         /** @hide */
         @Override
+        public boolean isHapticFeedbackCandidate() {
+            return mEffect.isHapticFeedbackCandidate();
+        }
+
+        /** @hide */
+        @Override
         public void validate() {
             mEffect.validate();
         }
@@ -431,6 +451,17 @@
 
         /** @hide */
         @Override
+        public boolean isHapticFeedbackCandidate() {
+            for (int i = 0; i < mEffects.size(); i++) {
+                if (!mEffects.valueAt(i).isHapticFeedbackCandidate()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /** @hide */
+        @Override
         public void validate() {
             Preconditions.checkArgument(mEffects.size() > 0,
                     "There should be at least one effect set for a combined effect");
@@ -513,6 +544,9 @@
      */
     @TestApi
     public static final class Sequential extends CombinedVibration {
+        // If a vibration is playing more than 3 effects, it's probably not haptic feedback
+        private static final long MAX_HAPTIC_FEEDBACK_SEQUENCE_SIZE = 3;
+
         private final List<CombinedVibration> mEffects;
         private final List<Integer> mDelays;
 
@@ -575,6 +609,21 @@
 
         /** @hide */
         @Override
+        public boolean isHapticFeedbackCandidate() {
+            final int effectCount = mEffects.size();
+            if (effectCount > MAX_HAPTIC_FEEDBACK_SEQUENCE_SIZE) {
+                return false;
+            }
+            for (int i = 0; i < effectCount; i++) {
+                if (!mEffects.get(i).isHapticFeedbackCandidate()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /** @hide */
+        @Override
         public void validate() {
             Preconditions.checkArgument(mEffects.size() > 0,
                     "There should be at least one effect set for a combined effect");
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 8308e8e..3f42164 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -60,6 +60,7 @@
     List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated);
     List<UserInfo> getProfiles(int userId, boolean enabledOnly);
     int[] getProfileIds(int userId, boolean enabledOnly);
+    boolean isUserTypeEnabled(in String userType);
     boolean canAddMoreUsersOfType(in String userType);
     boolean canAddMoreProfilesToUser(in String userType, int userId, boolean allowedToRemoveOne);
     boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index a828268..d0d6cb7 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -196,9 +196,6 @@
             return;
         }
         CombinedVibration combinedEffect = CombinedVibration.createParallel(effect);
-        // TODO(b/185351540): move this into VibratorManagerService once the touch vibration
-        // heuristics is fixed and works for CombinedVibration. Make sure it's always applied.
-        attributes = new VibrationAttributes.Builder(attributes, effect).build();
         mVibratorManager.vibrate(uid, opPkg, combinedEffect, reason, attributes);
     }
 
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index e5622a3..c690df2 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -223,9 +223,6 @@
             CombinedVibration combined = CombinedVibration.startParallel()
                     .addVibrator(mVibratorInfo.getId(), vibe)
                     .combine();
-            // TODO(b/185351540): move this into VibratorManagerService once the touch vibration
-            // heuristics is fixed and works for CombinedVibration. Make sure it's always applied.
-            attributes = new VibrationAttributes.Builder(attributes, vibe).build();
             SystemVibratorManager.this.vibrate(uid, opPkg, combined, reason, attributes);
         }
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 79553e0..bc6dbd8 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3958,6 +3958,25 @@
     }
 
     /**
+     * Checks whether this device supports users of the given user type.
+     *
+     * @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_SECONDARY}.
+     * @return true if the creation of users of the given user type is enabled on this device.
+     * @hide
+     */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
+    public boolean isUserTypeEnabled(@NonNull String userType) {
+        try {
+            return mService.isUserTypeEnabled(userType);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns list of the profiles of userId including userId itself.
      * Note that this returns both enabled and not enabled profiles. See
      * {@link #getEnabledProfiles(int)} if you need only the enabled ones.
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 36cdfcc..9612ca6 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -21,9 +21,6 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.media.AudioAttributes;
-import android.os.vibrator.PrebakedSegment;
-import android.os.vibrator.VibrationEffectSegment;
-import android.util.Slog;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -156,9 +153,6 @@
      */
     public static final int FLAG_ALL_SUPPORTED = FLAG_BYPASS_INTERRUPTION_POLICY;
 
-    // If a vibration is playing for longer than 5s, it's probably not haptic feedback
-    private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
-
     /** Creates a new {@link VibrationAttributes} instance with given usage. */
     public static @NonNull VibrationAttributes createForUsage(int usage) {
         return new VibrationAttributes.Builder().setUsage(usage).build();
@@ -359,67 +353,6 @@
             setFlags(audio);
         }
 
-        /**
-         * Constructs a new Builder from AudioAttributes and a VibrationEffect to infer usage.
-         * @hide
-         */
-        @TestApi
-        public Builder(@NonNull AudioAttributes audio, @NonNull VibrationEffect effect) {
-            this(audio);
-            applyHapticFeedbackHeuristics(effect);
-        }
-
-        /**
-         * Constructs a new Builder from VibrationAttributes and a VibrationEffect to infer usage.
-         * @hide
-         */
-        @TestApi
-        public Builder(@NonNull VibrationAttributes vib, @NonNull VibrationEffect effect) {
-            this(vib);
-            applyHapticFeedbackHeuristics(effect);
-        }
-
-        private void applyHapticFeedbackHeuristics(@Nullable VibrationEffect effect) {
-            if (effect != null) {
-                PrebakedSegment prebaked = extractPrebakedSegment(effect);
-                if (mUsage == USAGE_UNKNOWN && prebaked != null) {
-                    switch (prebaked.getEffectId()) {
-                        case VibrationEffect.EFFECT_CLICK:
-                        case VibrationEffect.EFFECT_DOUBLE_CLICK:
-                        case VibrationEffect.EFFECT_HEAVY_CLICK:
-                        case VibrationEffect.EFFECT_TEXTURE_TICK:
-                        case VibrationEffect.EFFECT_TICK:
-                        case VibrationEffect.EFFECT_POP:
-                        case VibrationEffect.EFFECT_THUD:
-                            mUsage = USAGE_TOUCH;
-                            break;
-                        default:
-                            Slog.w(TAG, "Unknown prebaked vibration effect, assuming it isn't "
-                                    + "haptic feedback");
-                    }
-                }
-                final long duration = effect.getDuration();
-                if (mUsage == USAGE_UNKNOWN && duration >= 0
-                        && duration < MAX_HAPTIC_FEEDBACK_DURATION) {
-                    mUsage = USAGE_TOUCH;
-                }
-            }
-        }
-
-        @Nullable
-        private PrebakedSegment extractPrebakedSegment(VibrationEffect effect) {
-            if (effect instanceof VibrationEffect.Composed) {
-                VibrationEffect.Composed composed = (VibrationEffect.Composed) effect;
-                if (composed.getSegments().size() == 1) {
-                    VibrationEffectSegment segment = composed.getSegments().get(0);
-                    if (segment instanceof PrebakedSegment) {
-                        return (PrebakedSegment) segment;
-                    }
-                }
-            }
-            return null;
-        }
-
         private void setUsage(@NonNull AudioAttributes audio) {
             mOriginalAudioUsage = audio.getUsage();
             switch (audio.getUsage()) {
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index a0cbbfe..5758a4e 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -53,7 +53,10 @@
 public abstract class VibrationEffect implements Parcelable {
     // Stevens' coefficient to scale the perceived vibration intensity.
     private static final float SCALE_GAMMA = 0.65f;
-
+    // If a vibration is playing for longer than 1s, it's probably not haptic feedback
+    private static final long MAX_HAPTIC_FEEDBACK_DURATION = 1000;
+    // If a vibration is playing more than 3 constants, it's probably not haptic feedback
+    private static final long MAX_HAPTIC_FEEDBACK_COMPOSITION_SIZE = 3;
 
     /**
      * The default vibration strength of the device.
@@ -439,6 +442,20 @@
     public abstract long getDuration();
 
     /**
+     * Returns true if this effect could represent a touch haptic feedback.
+     *
+     * <p>It is strongly recommended that an instance of {@link VibrationAttributes} is specified
+     * for each vibration, with the correct usage. When a vibration is played with usage UNKNOWN,
+     * then this method will be used to classify the most common use case and make sure they are
+     * covered by the user settings for "Touch feedback".
+     *
+     * @hide
+     */
+    public boolean isHapticFeedbackCandidate() {
+        return false;
+    }
+
+    /**
      * Resolve default values into integer amplitude numbers.
      *
      * @param defaultAmplitude the default amplitude to apply, must be between 0 and
@@ -582,6 +599,7 @@
             return mRepeatIndex;
         }
 
+        /** @hide */
         @Override
         public void validate() {
             int segmentCount = mSegments.size();
@@ -620,6 +638,37 @@
             return totalDuration;
         }
 
+        /** @hide */
+        @Override
+        public boolean isHapticFeedbackCandidate() {
+            long totalDuration = getDuration();
+            if (totalDuration > MAX_HAPTIC_FEEDBACK_DURATION) {
+                // Vibration duration is known and is longer than the max duration used to classify
+                // haptic feedbacks (or repeating indefinitely with duration == Long.MAX_VALUE).
+                return false;
+            }
+            int segmentCount = mSegments.size();
+            if (segmentCount > MAX_HAPTIC_FEEDBACK_COMPOSITION_SIZE) {
+                // Vibration has some prebaked or primitive constants, it should be limited to the
+                // max composition size used to classify haptic feedbacks.
+                return false;
+            }
+            totalDuration = 0;
+            for (int i = 0; i < segmentCount; i++) {
+                if (!mSegments.get(i).isHapticFeedbackCandidate()) {
+                    // There is at least one segment that is not a candidate for a haptic feedback.
+                    return false;
+                }
+                long segmentDuration = mSegments.get(i).getDuration();
+                if (segmentDuration > 0) {
+                    totalDuration += segmentDuration;
+                }
+            }
+            // Vibration might still have some ramp or step segments, check the known duration.
+            return totalDuration <= MAX_HAPTIC_FEEDBACK_DURATION;
+        }
+
+        /** @hide */
         @NonNull
         @Override
         public Composed resolve(int defaultAmplitude) {
@@ -636,6 +685,7 @@
             return resolved;
         }
 
+        /** @hide */
         @NonNull
         @Override
         public Composed scale(float scaleFactor) {
@@ -652,6 +702,7 @@
             return scaled;
         }
 
+        /** @hide */
         @NonNull
         @Override
         public Composed applyEffectStrength(int effectStrength) {
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 75234db..c67c82e 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -493,7 +493,7 @@
         vibrate(vibe,
                 attributes == null
                         ? new VibrationAttributes.Builder().build()
-                        : new VibrationAttributes.Builder(attributes, vibe).build());
+                        : new VibrationAttributes.Builder(attributes).build());
     }
 
     /**
diff --git a/core/java/android/os/vibrator/PrebakedSegment.java b/core/java/android/os/vibrator/PrebakedSegment.java
index 78b4346..30f5a5c 100644
--- a/core/java/android/os/vibrator/PrebakedSegment.java
+++ b/core/java/android/os/vibrator/PrebakedSegment.java
@@ -67,17 +67,38 @@
         return -1;
     }
 
+    /** @hide */
+    @Override
+    public boolean isHapticFeedbackCandidate() {
+        switch (mEffectId) {
+            case VibrationEffect.EFFECT_CLICK:
+            case VibrationEffect.EFFECT_DOUBLE_CLICK:
+            case VibrationEffect.EFFECT_HEAVY_CLICK:
+            case VibrationEffect.EFFECT_POP:
+            case VibrationEffect.EFFECT_TEXTURE_TICK:
+            case VibrationEffect.EFFECT_THUD:
+            case VibrationEffect.EFFECT_TICK:
+                return true;
+            default:
+                // VibrationEffect.RINGTONES are not segments that could represent a haptic feedback
+                return false;
+        }
+    }
+
+    /** @hide */
     @Override
     public boolean hasNonZeroAmplitude() {
         return true;
     }
 
+    /** @hide */
     @NonNull
     @Override
     public PrebakedSegment resolve(int defaultAmplitude) {
         return this;
     }
 
+    /** @hide */
     @NonNull
     @Override
     public PrebakedSegment scale(float scaleFactor) {
@@ -85,6 +106,7 @@
         return this;
     }
 
+    /** @hide */
     @NonNull
     @Override
     public PrebakedSegment applyEffectStrength(int effectStrength) {
@@ -105,16 +127,17 @@
         }
     }
 
+    /** @hide */
     @Override
     public void validate() {
         switch (mEffectId) {
             case VibrationEffect.EFFECT_CLICK:
             case VibrationEffect.EFFECT_DOUBLE_CLICK:
-            case VibrationEffect.EFFECT_TICK:
+            case VibrationEffect.EFFECT_HEAVY_CLICK:
+            case VibrationEffect.EFFECT_POP:
             case VibrationEffect.EFFECT_TEXTURE_TICK:
             case VibrationEffect.EFFECT_THUD:
-            case VibrationEffect.EFFECT_POP:
-            case VibrationEffect.EFFECT_HEAVY_CLICK:
+            case VibrationEffect.EFFECT_TICK:
                 break;
             default:
                 int[] ringtones = VibrationEffect.RINGTONES;
diff --git a/core/java/android/os/vibrator/PrimitiveSegment.java b/core/java/android/os/vibrator/PrimitiveSegment.java
index 2ef29cb..58ca978 100644
--- a/core/java/android/os/vibrator/PrimitiveSegment.java
+++ b/core/java/android/os/vibrator/PrimitiveSegment.java
@@ -67,18 +67,27 @@
         return -1;
     }
 
+    /** @hide */
+    @Override
+    public boolean isHapticFeedbackCandidate() {
+        return true;
+    }
+
+    /** @hide */
     @Override
     public boolean hasNonZeroAmplitude() {
         // Every primitive plays a vibration with a non-zero amplitude, even at scale == 0.
         return true;
     }
 
+    /** @hide */
     @NonNull
     @Override
     public PrimitiveSegment resolve(int defaultAmplitude) {
         return this;
     }
 
+    /** @hide */
     @NonNull
     @Override
     public PrimitiveSegment scale(float scaleFactor) {
@@ -86,12 +95,14 @@
                 mDelay);
     }
 
+    /** @hide */
     @NonNull
     @Override
     public PrimitiveSegment applyEffectStrength(int effectStrength) {
         return this;
     }
 
+    /** @hide */
     @Override
     public void validate() {
         Preconditions.checkArgumentInRange(mPrimitiveId, VibrationEffect.Composition.PRIMITIVE_NOOP,
diff --git a/core/java/android/os/vibrator/RampSegment.java b/core/java/android/os/vibrator/RampSegment.java
index aad87c5..3ec5636 100644
--- a/core/java/android/os/vibrator/RampSegment.java
+++ b/core/java/android/os/vibrator/RampSegment.java
@@ -87,11 +87,19 @@
         return mDuration;
     }
 
+    /** @hide */
+    @Override
+    public boolean isHapticFeedbackCandidate() {
+        return true;
+    }
+
+    /** @hide */
     @Override
     public boolean hasNonZeroAmplitude() {
         return mStartAmplitude > 0 || mEndAmplitude > 0;
     }
 
+    /** @hide */
     @Override
     public void validate() {
         Preconditions.checkArgumentNonnegative(mDuration,
@@ -100,7 +108,7 @@
         Preconditions.checkArgumentInRange(mEndAmplitude, 0f, 1f, "endAmplitude");
     }
 
-
+    /** @hide */
     @NonNull
     @Override
     public RampSegment resolve(int defaultAmplitude) {
@@ -108,6 +116,7 @@
         return this;
     }
 
+    /** @hide */
     @NonNull
     @Override
     public RampSegment scale(float scaleFactor) {
@@ -121,6 +130,7 @@
                 mDuration);
     }
 
+    /** @hide */
     @NonNull
     @Override
     public RampSegment applyEffectStrength(int effectStrength) {
diff --git a/core/java/android/os/vibrator/StepSegment.java b/core/java/android/os/vibrator/StepSegment.java
index 11209e0..69a381f 100644
--- a/core/java/android/os/vibrator/StepSegment.java
+++ b/core/java/android/os/vibrator/StepSegment.java
@@ -73,12 +73,20 @@
         return mDuration;
     }
 
+    /** @hide */
+    @Override
+    public boolean isHapticFeedbackCandidate() {
+        return true;
+    }
+
+    /** @hide */
     @Override
     public boolean hasNonZeroAmplitude() {
         // DEFAULT_AMPLITUDE == -1 is still a non-zero amplitude that will be resolved later.
         return Float.compare(mAmplitude, 0) != 0;
     }
 
+    /** @hide */
     @Override
     public void validate() {
         Preconditions.checkArgumentNonnegative(mDuration,
@@ -88,6 +96,7 @@
         }
     }
 
+    /** @hide */
     @NonNull
     @Override
     public StepSegment resolve(int defaultAmplitude) {
@@ -103,6 +112,7 @@
                 mDuration);
     }
 
+    /** @hide */
     @NonNull
     @Override
     public StepSegment scale(float scaleFactor) {
@@ -113,6 +123,7 @@
                 mDuration);
     }
 
+    /** @hide */
     @NonNull
     @Override
     public StepSegment applyEffectStrength(int effectStrength) {
diff --git a/core/java/android/os/vibrator/VibrationEffectSegment.java b/core/java/android/os/vibrator/VibrationEffectSegment.java
index 5b42845..979c447 100644
--- a/core/java/android/os/vibrator/VibrationEffectSegment.java
+++ b/core/java/android/os/vibrator/VibrationEffectSegment.java
@@ -57,10 +57,26 @@
      */
     public abstract long getDuration();
 
-    /** Returns true if this segment plays at a non-zero amplitude at some point. */
+    /**
+     * Returns true if this segment could be a haptic feedback effect candidate.
+     *
+     * @see VibrationEffect#isHapticFeedbackCandidate()
+     * @hide
+     */
+    public abstract boolean isHapticFeedbackCandidate();
+
+    /**
+     * Returns true if this segment plays at a non-zero amplitude at some point.
+     *
+     * @hide
+     */
     public abstract boolean hasNonZeroAmplitude();
 
-    /** Validates the segment, throwing exceptions if any parameter is invalid. */
+    /**
+     * Validates the segment, throwing exceptions if any parameter is invalid.
+     *
+     * @hide
+     */
     public abstract void validate();
 
     /**
@@ -68,6 +84,8 @@
      *
      * <p>This might fail with {@link IllegalArgumentException} if value is non-positive or larger
      * than {@link VibrationEffect#MAX_AMPLITUDE}.
+     *
+     * @hide
      */
     @NonNull
     public abstract <T extends VibrationEffectSegment> T resolve(int defaultAmplitude);
@@ -77,6 +95,8 @@
      *
      * @param scaleFactor scale factor to be applied to the intensity. Values within [0,1) will
      *                    scale down the intensity, values larger than 1 will scale up
+     *
+     * @hide
      */
     @NonNull
     public abstract <T extends VibrationEffectSegment> T scale(float scaleFactor);
@@ -86,6 +106,8 @@
      *
      * @param effectStrength new effect strength to be applied, one of
      *                       VibrationEffect.EFFECT_STRENGTH_*.
+     *
+     * @hide
      */
     @NonNull
     public abstract <T extends VibrationEffectSegment> T applyEffectStrength(int effectStrength);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d3b1b40..7979256 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12014,8 +12014,10 @@
          * Value to specify whether network quality scores and badging should be shown in the UI.
          *
          * Type: int (0 for false, 1 for true)
+         * @deprecated {@code NetworkScoreManager} is deprecated.
          * @hide
          */
+        @Deprecated
         @Readable
         public static final String NETWORK_SCORING_UI_ENABLED = "network_scoring_ui_enabled";
 
@@ -12024,8 +12026,10 @@
          * when generating SSID only bases score curves.
          *
          * Type: long
+         * @deprecated {@code NetworkScoreManager} is deprecated.
          * @hide
          */
+        @Deprecated
         @Readable
         public static final String SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS =
                 "speed_label_cache_eviction_age_millis";
@@ -12058,8 +12062,10 @@
          * {@link NetworkScoreManager#setActiveScorer(String)} to write it.
          *
          * Type: string - package name
+         * @deprecated {@code NetworkScoreManager} is deprecated.
          * @hide
          */
+        @Deprecated
         @Readable
         public static final String NETWORK_RECOMMENDATIONS_PACKAGE =
                 "network_recommendations_package";
@@ -12069,8 +12075,10 @@
          * networks automatically.
          *
          * Type: string package name or null if the feature is either not provided or disabled.
+         * @deprecated {@code NetworkScoreManager} is deprecated.
          * @hide
          */
+        @Deprecated
         @TestApi
         @Readable
         public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
@@ -12080,8 +12088,10 @@
          * {@link com.android.server.wifi.RecommendedNetworkEvaluator}.
          *
          * Type: long
+         * @deprecated {@code NetworkScoreManager} is deprecated.
          * @hide
          */
+        @Deprecated
         @Readable
         public static final String RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS =
                 "recommended_network_evaluator_cache_expiry_ms";
diff --git a/core/java/android/security/attestationverification/AttestationProfile.aidl b/core/java/android/security/attestationverification/AttestationProfile.aidl
new file mode 100644
index 0000000..51696a9
--- /dev/null
+++ b/core/java/android/security/attestationverification/AttestationProfile.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+/**
+ * {@hide}
+ */
+parcelable AttestationProfile;
diff --git a/core/java/android/security/attestationverification/AttestationProfile.java b/core/java/android/security/attestationverification/AttestationProfile.java
new file mode 100644
index 0000000..7a43dac
--- /dev/null
+++ b/core/java/android/security/attestationverification/AttestationProfile.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+import static android.security.attestationverification.AttestationVerificationManager.PROFILE_APP_DEFINED;
+import static android.security.attestationverification.AttestationVerificationManager.PROFILE_UNKNOWN;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+import android.security.attestationverification.AttestationVerificationManager.AttestationProfileId;
+import android.util.Log;
+
+import com.android.internal.util.DataClass;
+
+
+/**
+ * An attestation profile defining the security requirements for verifying the attestation of a
+ * remote compute environment.
+ *
+ * <p>This class is immutable and thread-safe. When checking this profile against an expected
+ * profile, it is recommended to construct the expected profile and compare them with {@code
+ * equals()}.
+ *
+ * @hide
+ * @see AttestationVerificationManager
+ */
+@DataClass(
+        genConstructor = false,
+        genEqualsHashCode = true
+)
+public final class AttestationProfile implements Parcelable {
+
+    private static final String TAG = "AVF";
+
+    /**
+     * The ID of a system-defined attestation profile.
+     *
+     * See constants in {@link AttestationVerificationManager} prefixed with {@code PROFILE_}. If
+     * this has the value of {@link AttestationVerificationManager#PROFILE_APP_DEFINED}, then the
+     * packageName and profileName are non-null.
+     */
+    @AttestationProfileId
+    private final int mAttestationProfileId;
+
+    /**
+     * The package name of a app-defined attestation profile.
+     *
+     * This value will be null unless the value of attestationProfileId is {@link
+     * AttestationVerificationManager#PROFILE_APP_DEFINED}.
+     */
+    @Nullable
+    private final String mPackageName;
+
+
+    /**
+     * The name of an app-defined attestation profile.
+     *
+     * This value will be null unless the value of attestationProfileId is {@link
+     * AttestationVerificationManager#PROFILE_APP_DEFINED}.
+     */
+    @Nullable
+    private final String mProfileName;
+
+    private AttestationProfile(
+            @AttestationProfileId int attestationProfileId,
+            @Nullable String packageName,
+            @Nullable String profileName) {
+        mAttestationProfileId = attestationProfileId;
+        mPackageName = packageName;
+        mProfileName = profileName;
+    }
+
+    /**
+     * Create a profile with the given id.
+     *
+     * <p>This constructor is for specifying a profile which is defined by the system. These are
+     * available as constants in the {@link AttestationVerificationManager} class prefixed with
+     * {@code PROFILE_}.
+     *
+     * @param attestationProfileId the ID of the system-defined profile
+     * @throws IllegalArgumentException when called with
+     * {@link AttestationVerificationManager#PROFILE_APP_DEFINED}
+     *                                  (use {@link #AttestationProfile(String, String)})
+     */
+    public AttestationProfile(@AttestationProfileId int attestationProfileId) {
+        this(attestationProfileId, null, null);
+        if (attestationProfileId == PROFILE_APP_DEFINED) {
+            throw new IllegalArgumentException("App-defined profiles must be specified with the "
+                    + "constructor AttestationProfile#constructor(String, String)");
+        }
+    }
+
+    /**
+     * Create a profile with the given package name and profile name.
+     *
+     * <p>This constructor is for specifying a profile defined by an app. The packageName must
+     * match the package name of the app that defines the profile (as specified in the {@code
+     * package} attribute of the {@code
+     * <manifest>} tag in the app's manifest. The profile name matches the {@code name} attribute
+     * of the {@code <attestation-profile>} tag.
+     *
+     * <p>Apps must declare profiles in their manifest as an {@code <attestation-profile>} element.
+     * However, this constructor does not verify that such a profile exists. If the profile does not
+     * exist, verifications will fail.
+     *
+     * @param packageName the package name of the app defining the profile
+     * @param profileName the name of the profile
+     */
+    public AttestationProfile(@NonNull String packageName, @NonNull String profileName) {
+        this(PROFILE_APP_DEFINED, packageName, profileName);
+        if (packageName == null || profileName == null) {
+            throw new IllegalArgumentException("Both packageName and profileName must be non-null");
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (mAttestationProfileId == PROFILE_APP_DEFINED) {
+            return "AttestationProfile(package=" + mPackageName + ", name=" + mProfileName + ")";
+        } else {
+            String humanReadableProfileId;
+            switch (mAttestationProfileId) {
+                case PROFILE_UNKNOWN:
+                    humanReadableProfileId = "PROFILE_UNKNOWN";
+                    break;
+                default:
+                    Log.e(TAG, "ERROR: Missing case in AttestationProfile#toString");
+                    humanReadableProfileId = "ERROR";
+            }
+            return "AttestationProfile(" + humanReadableProfileId + "/" + mAttestationProfileId
+                    + ")";
+        }
+    }
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/security
+    // /attestationverification/AttestationProfile.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * The ID of a system-defined attestation profile.
+     *
+     * See constants in {@link AttestationVerificationManager} prefixed with {@code PROFILE_}. If
+     * this has the value of {@link AttestationVerificationManager#PROFILE_APP_DEFINED}, then the
+     * packageName and profileName are non-null.
+     */
+    @DataClass.Generated.Member
+    public @AttestationProfileId int getAttestationProfileId() {
+        return mAttestationProfileId;
+    }
+
+    /**
+     * The package name of a app-defined attestation profile.
+     *
+     * This value will be null unless the value of attestationProfileId is {@link
+     * AttestationVerificationManager#PROFILE_APP_DEFINED}.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * The name of an app-defined attestation profile.
+     *
+     * This value will be null unless the value of attestationProfileId is {@link
+     * AttestationVerificationManager#PROFILE_APP_DEFINED}.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getProfileName() {
+        return mProfileName;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(AttestationProfile other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        AttestationProfile that = (AttestationProfile) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mAttestationProfileId == that.mAttestationProfileId
+                && java.util.Objects.equals(mPackageName, that.mPackageName)
+                && java.util.Objects.equals(mProfileName, that.mProfileName);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mAttestationProfileId;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mPackageName);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mProfileName);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mPackageName != null) flg |= 0x2;
+        if (mProfileName != null) flg |= 0x4;
+        dest.writeByte(flg);
+        dest.writeInt(mAttestationProfileId);
+        if (mPackageName != null) dest.writeString(mPackageName);
+        if (mProfileName != null) dest.writeString(mProfileName);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ AttestationProfile(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int attestationProfileId = in.readInt();
+        String packageName = (flg & 0x2) == 0 ? null : in.readString();
+        String profileName = (flg & 0x4) == 0 ? null : in.readString();
+
+        this.mAttestationProfileId = attestationProfileId;
+        com.android.internal.util.AnnotationValidations.validate(
+                AttestationProfileId.class, null, mAttestationProfileId);
+        this.mPackageName = packageName;
+        this.mProfileName = profileName;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<AttestationProfile> CREATOR
+            = new Parcelable.Creator<AttestationProfile>() {
+        @Override
+        public AttestationProfile[] newArray(int size) {
+            return new AttestationProfile[size];
+        }
+
+        @Override
+        public AttestationProfile createFromParcel(@NonNull android.os.Parcel in) {
+            return new AttestationProfile(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1633629498403L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/security/attestationverification/AttestationProfile.java",
+            inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.security.attestationverification.AttestationVerificationManager.AttestationProfileId int mAttestationProfileId\nprivate final @android.annotation.Nullable java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mProfileName\npublic @java.lang.Override java.lang.String toString()\nclass AttestationProfile extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/security/attestationverification/AttestationVerificationManager.java b/core/java/android/security/attestationverification/AttestationVerificationManager.java
new file mode 100644
index 0000000..db783ce
--- /dev/null
+++ b/core/java/android/security/attestationverification/AttestationVerificationManager.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelDuration;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.time.Duration;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
+
+/**
+ * Provides methods for verifying that attestations from remote compute environments meet minimum
+ * security requirements specified by attestation profiles.
+ *
+ * @hide
+ */
+@SystemService(Context.ATTESTATION_VERIFICATION_SERVICE)
+public class AttestationVerificationManager {
+
+    private static final String TAG = "AVF";
+    private static final Duration MAX_TOKEN_AGE = Duration.ofHours(1);
+
+    private final Context mContext;
+    private final IAttestationVerificationManagerService mService;
+
+    /**
+     * Verifies that {@code attestation} describes a computing environment that meets the
+     * requirements of {@code profile}, {@code localBindingType}, and {@code requirements}.
+     *
+     * <p>This method verifies that at least one system-registered {@linkplain
+     * AttestationVerificationService attestation verifier} associated with {@code profile} and
+     * {@code localBindingType} has verified that {@code attestation} attests that the remote
+     * environment matching the local binding data (determined by {@code localBindingType}) in
+     * {@code requirements} meets the requirements of the profile.
+     *
+     * <p>For successful verification, the {@code requirements} bundle must contain locally-known
+     * data which must match {@code attestation}. The required data in the bundle is defined by the
+     * {@code localBindingType} (see documentation for the type). Verifiers will fail to verify the
+     * attestation if the bundle contains unsupported data.
+     *
+     * <p>The {@code localBindingType} specifies how {@code attestation} is bound to a local
+     * secure channel endpoint or similar connection with the target remote environment described by
+     * the attestation. The binding is expected to be related to a cryptographic protocol, and each
+     * binding type requires specific arguments to be present in the {@code requirements} bundle. It
+     * is this binding to something known locally that ensures an attestation is not only valid, but
+     * is also associated with a particular connection.
+     *
+     * <p>The {@code callback} is called with a result and {@link VerificationToken} (which may be
+     * null). The result is an integer (see constants in this class with the prefix {@code RESULT_}.
+     * The result is {@link #RESULT_SUCCESS} when at least one verifier has passed its checks. The
+     * token may be used in calls to other parts of the system.
+     *
+     * <p>It's expected that a verifier will be able to decode and understand the passed values,
+     * otherwise fail to verify. {@code attestation} should contain some type data to prevent parse
+     * errors.
+     *
+     * <p>The values put into the {@code requirements} Bundle depend on the {@code
+     * localBindingType} used.
+     *
+     * @param profile          the attestation profile which defines the security requirements which
+     *                         must be met by the environment described by {@code attestation}
+     * @param localBindingType the type of the local binding data; see constants in this class with
+     *                         the prefix {@code TYPE_}
+     * @param requirements     a {@link Bundle} containing locally-known data which must match
+     *                         {@code attestation}
+     * @param attestation      attestation data which describes a remote computing environment
+     * @param executor         {@code callback} will be executed on this executor
+     * @param callback         will be called with the results of the verification
+     * @see AttestationVerificationService
+     */
+    @RequiresPermission(Manifest.permission.USE_ATTESTATION_VERIFICATION_SERVICE)
+    public void verifyAttestation(
+            @NonNull AttestationProfile profile,
+            @LocalBindingType int localBindingType,
+            @NonNull Bundle requirements,
+            @NonNull byte[] attestation,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BiConsumer<@VerificationResult Integer, VerificationToken> callback) {
+        try {
+            AndroidFuture<IVerificationResult> resultCallback = new AndroidFuture<>();
+            resultCallback.thenAccept(result -> {
+                Log.d(TAG, "verifyAttestation result: " + result.resultCode + " / " + result.token);
+                executor.execute(() -> {
+                    callback.accept(result.resultCode, result.token);
+                });
+            });
+
+            mService.verifyAttestation(profile, localBindingType, requirements, attestation,
+                    resultCallback);
+
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Verifies that {@code token} is a valid token, returning the result contained in valid
+     * tokens.
+     *
+     * <p>This verifies that the token was issued by the platform and thus the system verified
+     * attestation data against the specified {@code profile}, {@code localBindingType}, and {@code
+     * requirements}. The value returned by this method is the same as the one originally returned
+     * when the token was generated. Callers of this method should not trust the provider of the
+     * token to also specify the profile, local binding type, or requirements, but instead have
+     * their own security requirements about these arguments.
+     *
+     * <p>This method, in contrast to {@code verifyAttestation}, executes synchronously and only
+     * checks that a previous verification succeeded. This allows callers to pass the token to
+     * others, including system APIs, without those components needing to re-verify the attestation
+     * data, an operation which can take several seconds.
+     *
+     * <p>When {@code maximumAge} is not specified (null), this method verifies the token was
+     * generated in the past hour. Otherwise, it verifies the token was generated between now and
+     * {@code maximumAge} ago. The maximum value of {@code maximumAge} is one hour; specifying a
+     * duration greater than one hour will result in an {@link IllegalArgumentException}.
+     *
+     * @param profile          the attestation profile which must be in the token
+     * @param localBindingType the local binding type which must be in the token
+     * @param requirements     the requirements which must be in the token
+     * @param token            the token to be verified
+     * @param maximumAge       the maximum age to accept for the token
+     */
+    @RequiresPermission(Manifest.permission.USE_ATTESTATION_VERIFICATION_SERVICE)
+    @CheckResult
+    @VerificationResult
+    public int verifyToken(
+            @NonNull AttestationProfile profile,
+            @LocalBindingType int localBindingType,
+            @NonNull Bundle requirements,
+            @NonNull VerificationToken token,
+            @Nullable Duration maximumAge) {
+        Duration usedMaximumAge;
+        if (maximumAge == null) {
+            usedMaximumAge = MAX_TOKEN_AGE;
+        } else {
+            if (maximumAge.compareTo(MAX_TOKEN_AGE) > 0) {
+                throw new IllegalArgumentException(
+                        "maximumAge cannot be greater than " + MAX_TOKEN_AGE + "; was "
+                                + maximumAge);
+            }
+            usedMaximumAge = maximumAge;
+        }
+
+        try {
+            AndroidFuture<Integer> resultCallback = new AndroidFuture<>();
+            resultCallback.orTimeout(5, TimeUnit.SECONDS);
+
+            mService.verifyToken(token, new ParcelDuration(usedMaximumAge), resultCallback);
+            return resultCallback.get(); // block on result callback
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (Throwable t) {
+            throw new RuntimeException("Error verifying token.", t);
+        }
+    }
+
+    /** @hide */
+    public AttestationVerificationManager(
+            @NonNull Context context,
+            @NonNull IAttestationVerificationManagerService service) {
+        this.mContext = context;
+        this.mService = service;
+    }
+
+    /** @hide */
+    @IntDef(
+            prefix = {"PROFILE_"},
+            value = {
+                    PROFILE_UNKNOWN,
+                    PROFILE_APP_DEFINED,
+                    PROFILE_SELF_TRUSTED,
+                    PROFILE_PEER_DEVICE,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AttestationProfileId {
+    }
+
+    /**
+     * The profile is unknown because it is a profile unknown to this version of the SDK.
+     */
+    public static final int PROFILE_UNKNOWN = 0;
+
+    /** The profile is defined by an app. */
+    public static final int PROFILE_APP_DEFINED = 1;
+
+    /**
+     * A system-defined profile which verifies that the attesting environment can create an
+     * attestation with the same root certificate as the verifying device with a matching
+     * attestation challenge.
+     *
+     * This profile is intended to be used only for testing.
+     */
+    public static final int PROFILE_SELF_TRUSTED = 2;
+
+    /**
+     * A system-defined profile which verifies that the attesting environment environment is similar
+     * to the current device in terms of security model and security configuration. This category is
+     * fairly broad and most securely configured Android devices should qualify, along with a
+     * variety of non-Android devices.
+     */
+    public static final int PROFILE_PEER_DEVICE = 3;
+
+    /** @hide */
+    @IntDef(
+            prefix = {"TYPE_"},
+            value = {
+                    TYPE_UNKNOWN,
+                    TYPE_APP_DEFINED,
+                    TYPE_PUBLIC_KEY,
+                    TYPE_CHALLENGE,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LocalBindingType {
+    }
+
+    /**
+     * The type of the local binding data is unknown because it is a type unknown to this version of
+     * the SDK.
+     */
+    public static final int TYPE_UNKNOWN = 0;
+
+    /**
+     * A local binding type for app-defined profiles which use local binding data which does not
+     * match any of the existing system-defined types.
+     */
+    public static final int TYPE_APP_DEFINED = 1;
+
+    /**
+     * A local binding type where the attestation is bound to a public key negotiated and
+     * authenticated to a public key.
+     *
+     * <p>When using this type, the {@code requirements} bundle contains values for:
+     * <ul>
+     *   <li>{@link #PARAM_PUBLIC_KEY}
+     *   <li>{@link #PARAM_ID}: identifying the remote environment, optional
+     * </ul>
+     */
+    public static final int TYPE_PUBLIC_KEY = 2;
+
+    /**
+     * A local binding type where the attestation is bound to a challenge.
+     *
+     * <p>When using this type, the {@code requirements} bundle contains values for:
+     * <ul>
+     *   <li>{@link #PARAM_CHALLENGE}: containing the challenge
+     * </ul>
+     */
+    public static final int TYPE_CHALLENGE = 3;
+
+    /** @hide */
+    @IntDef(
+            prefix = {"RESULT_"},
+            value = {
+                    RESULT_UNKNOWN,
+                    RESULT_SUCCESS,
+                    RESULT_FAILURE,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+    public @interface VerificationResult {
+    }
+
+    /** The result of the verification is unknown because it has a value unknown to this SDK. */
+    public static final int RESULT_UNKNOWN = 0;
+
+    /** The result of the verification was successful. */
+    public static final int RESULT_SUCCESS = 1;
+
+    /**
+     * The result of the attestation verification was failure. The attestation could not be
+     * verified.
+     */
+    public static final int RESULT_FAILURE = 2;
+
+    /**
+     * Requirements bundle parameter key for a public key, a byte array.
+     *
+     * <p>This should contain the encoded key bytes according to the ASN.1 type
+     * {@code SubjectPublicKeyInfo} defined in the X.509 standard, the same as a call to {@link
+     * java.security.spec.X509EncodedKeySpec#getEncoded()} would produce.
+     *
+     * @see Bundle#putByteArray(String, byte[])
+     */
+    public static final String PARAM_PUBLIC_KEY = "localbinding.public_key";
+
+    /** Requirements bundle parameter key for an ID, String. */
+    public static final String PARAM_ID = "localbinding.id";
+
+    /** Requirements bundle parameter for a challenge. */
+    public static final String PARAM_CHALLENGE = "localbinding.challenge";
+}
diff --git a/core/java/android/security/attestationverification/AttestationVerificationService.java b/core/java/android/security/attestationverification/AttestationVerificationService.java
new file mode 100644
index 0000000..26c3051
--- /dev/null
+++ b/core/java/android/security/attestationverification/AttestationVerificationService.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+import android.annotation.CheckResult;
+import android.annotation.NonNull;
+import android.app.Service;
+import android.os.Bundle;
+import android.security.attestationverification.AttestationVerificationManager.VerificationResult;
+
+/**
+ * A verifier which can be implemented by apps to verify an attestation (as described in {@link
+ * AttestationVerificationManager}).
+ *
+ * In the manifest for this service, specify the profile and local binding type this verifier
+ * supports. Create a new service for each combination of profile & local binding type that your app
+ * supports. Each service must declare an {@code intent-filter} action of {@link #SERVICE_INTERFACE}
+ * and permission of {@link android.Manifest.permission#BIND_ATTESTATION_VERIFICATION_SERVICE}.
+ *
+ * <p>Example:
+ * {@code
+ * <pre>
+ * <service android:name=".MyAttestationVerificationService"
+ *          android:permission="android.permission.BIND_ATTESTATION_VERIFICATION_SERVICE"
+ *          android:exported="true">
+ *   <intent-filter>
+ *     <action
+ *         android:name="android.security.attestationverification.AttestationVerificationService" />
+ *   </intent-filter>
+ *   <meta-data android:name="android.security.attestationverification.PROFILE_ID"
+ *              android:value="PROFILE_PLACEHOLDER_0" />
+ *   <meta-data android:name="android.security.attestationverification.LOCAL_BINDING_TYPE"
+ *              android:value="TYPE_PLACEHOLDER_0" />
+ * </service>
+ * </pre>
+ * }
+ *
+ * <p>For app-defined profiles, an example of the {@code <meta-data>}:
+ * {@code
+ * <pre>
+ *   <meta-data android:name="android.security.attestation.PROFILE_PACKAGE_NAME"
+ *              android:value="com.example" />
+ *   <meta-data android:name="android.security.attestation.PROFILE_NAME"
+ *              android:value="com.example.profile.PROFILE_FOO" />
+ * </pre>
+ * }
+ *
+ * @hide
+ */
+public abstract class AttestationVerificationService extends Service {
+
+    /**
+     * An intent action for a service to be bound and act as an attestation verifier.
+     *
+     * <p>The app will be kept alive for a short duration between verification calls after which
+     * the system will unbind from this service making the app eligible for cleanup.
+     *
+     * <p>The service must also require permission
+     * {@link android.Manifest.permission#BIND_ATTESTATION_VERIFICATION_SERVICE}.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.security.attestationverification.AttestationVerificationService";
+
+    /**
+     * Verifies that {@code attestation} attests that the device identified by the local binding
+     * data in {@code requirements} meets the minimum requirements of this verifier for this
+     * verifier's profile.
+     *
+     * <p>Called by the system to verify an attestation.
+     *
+     * <p>The data passed into this method comes directly from apps and should be treated as
+     * potentially dangerous user input.
+     *
+     * @param requirements a {@link Bundle} containing locally-known data which must match {@code
+     *                     attestation}
+     * @param attestation  the attestation to verify
+     * @return whether the verification passed
+     * @see AttestationVerificationManager#verifyAttestation(AttestationProfile, int, Bundle,
+     * byte[], java.util.concurrent.Executor, java.util.function.BiConsumer)
+     */
+    @CheckResult
+    @VerificationResult
+    public abstract int onVerifyPeerDeviceAttestation(
+            @NonNull Bundle requirements,
+            @NonNull byte[] attestation);
+}
diff --git a/core/java/android/security/attestationverification/IAttestationVerificationManagerService.aidl b/core/java/android/security/attestationverification/IAttestationVerificationManagerService.aidl
new file mode 100644
index 0000000..2fb328c
--- /dev/null
+++ b/core/java/android/security/attestationverification/IAttestationVerificationManagerService.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 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.security.attestationverification;
+
+import android.os.Bundle;
+import android.os.ParcelDuration;
+import android.security.attestationverification.AttestationProfile;
+import android.security.attestationverification.VerificationToken;
+import com.android.internal.infra.AndroidFuture;
+
+
+/**
+ * Binder interface to communicate with AttestationVerificationManagerService.
+ * @hide
+ */
+oneway interface IAttestationVerificationManagerService {
+
+    void verifyAttestation(
+            in AttestationProfile profile,
+            in int localBindingType,
+            in Bundle requirements,
+            in byte[] attestation,
+            in AndroidFuture resultCallback);
+
+    void verifyToken(
+            in VerificationToken token,
+            in ParcelDuration maximumTokenAge,
+            in AndroidFuture resultCallback);
+}
diff --git a/core/java/android/security/attestationverification/IAttestationVerificationService.aidl b/core/java/android/security/attestationverification/IAttestationVerificationService.aidl
new file mode 100644
index 0000000..082ad32
--- /dev/null
+++ b/core/java/android/security/attestationverification/IAttestationVerificationService.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+import android.os.Bundle;
+import com.android.internal.infra.AndroidFuture;
+
+
+/**
+ * Binder interface for the system server to communicate with app implementations of
+ * AttestationVerificationService.
+ * @hide
+ */
+oneway interface IAttestationVerificationService {
+    void onVerifyAttestation(
+        in Bundle requirements,
+        in byte[] attestation,
+        in AndroidFuture callback);
+}
diff --git a/core/java/android/security/attestationverification/IVerificationResult.aidl b/core/java/android/security/attestationverification/IVerificationResult.aidl
new file mode 100644
index 0000000..f61c456
--- /dev/null
+++ b/core/java/android/security/attestationverification/IVerificationResult.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+import android.security.attestationverification.VerificationToken;
+
+
+/**
+ * The result of an attestation verification.
+ *
+ * {@hide}
+ */
+parcelable IVerificationResult {
+    /** The result code corresponding to @VerificationResult. */
+    int resultCode;
+    /** The token for the verification or null. */
+    VerificationToken token;
+}
diff --git a/core/java/android/security/attestationverification/VerificationToken.aidl b/core/java/android/security/attestationverification/VerificationToken.aidl
new file mode 100644
index 0000000..666a8b0
--- /dev/null
+++ b/core/java/android/security/attestationverification/VerificationToken.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+/**
+ * {@hide}
+ */
+parcelable VerificationToken;
diff --git a/core/java/android/security/attestationverification/VerificationToken.java b/core/java/android/security/attestationverification/VerificationToken.java
new file mode 100644
index 0000000..ae26823
--- /dev/null
+++ b/core/java/android/security/attestationverification/VerificationToken.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2021 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.security.attestationverification;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.security.attestationverification.AttestationVerificationManager.LocalBindingType;
+import android.security.attestationverification.AttestationVerificationManager.VerificationResult;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForInstant;
+
+import java.time.Duration;
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
+
+/**
+ * Token representing the result of an attestation verification, which can be passed to other parts
+ * of the OS or other apps as proof of the verification.
+ *
+ * Tokens are only valid within the same UID (which means within a single app unless the deprecated
+ * android:sharedUserId manifest value is used).
+ *
+ * @hide
+ * @see Bundle#putParcelable(String, Parcelable)
+ */
+@DataClass(
+        genConstructor = false,
+        genHiddenBuilder = true
+)
+public final class VerificationToken implements Parcelable {
+
+    /**
+     * The attestation profile which was used to perform the verification.
+     * @hide
+     */
+    @NonNull
+    private final AttestationProfile mAttestationProfile;
+
+    /**
+     * The local binding type of the local binding data used to perform the verification.
+     * @hide
+     */
+    @LocalBindingType
+    private final int mLocalBindingType;
+
+    /**
+     * The requirements used to perform the verification.
+     * @hide
+     */
+    @NonNull
+    private final Bundle mRequirements;
+
+    /**
+     * The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
+     * byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
+     * accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
+     * value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
+     * Duration)} to verify a valid token and it will return this value.
+     *
+     * If the token is valid, this value is returned directly by {#verifyToken}.
+     *
+     * @hide
+     */
+    @VerificationResult
+    private final int mVerificationResult;
+
+    /**
+     * Time when the token was generated, set by the system.
+     */
+    @NonNull
+    @DataClass.ParcelWith(ForInstant.class)
+    private final java.time.Instant mVerificationTime;
+
+    /**
+     * A Hash-based message authentication code used to verify the contents and authenticity of the
+     * rest of the token. The hash is created using a secret key known only to the system server.
+     * When verifying the token, the system re-hashes the token and verifies the generated HMAC is
+     * the same.
+     *
+     * @hide
+     */
+    @NonNull
+    private final byte[] mHmac;
+
+    /**
+     * The UID of the process which called {@code verifyAttestation} to create the token, as
+     * returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
+     * of calling process does not match this value. This ensures that tokens cannot be shared
+     * between UIDs.
+     *
+     * @hide
+     */
+    private int mUid;
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/security/attestationverification/VerificationToken.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ VerificationToken(
+            @NonNull AttestationProfile attestationProfile,
+            @LocalBindingType int localBindingType,
+            @NonNull Bundle requirements,
+            @VerificationResult int verificationResult,
+            @NonNull java.time.Instant verificationTime,
+            @NonNull byte[] hmac,
+            int uid) {
+        this.mAttestationProfile = attestationProfile;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAttestationProfile);
+        this.mLocalBindingType = localBindingType;
+        com.android.internal.util.AnnotationValidations.validate(
+                LocalBindingType.class, null, mLocalBindingType);
+        this.mRequirements = requirements;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mRequirements);
+        this.mVerificationResult = verificationResult;
+        com.android.internal.util.AnnotationValidations.validate(
+                VerificationResult.class, null, mVerificationResult);
+        this.mVerificationTime = verificationTime;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mVerificationTime);
+        this.mHmac = hmac;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHmac);
+        this.mUid = uid;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The attestation profile which was used to perform the verification.
+     */
+    @DataClass.Generated.Member
+    public @NonNull AttestationProfile getAttestationProfile() {
+        return mAttestationProfile;
+    }
+
+    /**
+     * The local binding type of the local binding data used to perform the verification.
+     */
+    @DataClass.Generated.Member
+    public @LocalBindingType int getLocalBindingType() {
+        return mLocalBindingType;
+    }
+
+    /**
+     * The requirements used to perform the verification.
+     */
+    @DataClass.Generated.Member
+    public @NonNull Bundle getRequirements() {
+        return mRequirements;
+    }
+
+    /**
+     * The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
+     * byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
+     * accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
+     * value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
+     * Duration)} to verify a valid token and it will return this value.
+     *
+     * If the token is valid, this value is returned directly by {#verifyToken}.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @VerificationResult int getVerificationResult() {
+        return mVerificationResult;
+    }
+
+    /**
+     * Time when the token was generated, set by the system.
+     */
+    @DataClass.Generated.Member
+    public @NonNull java.time.Instant getVerificationTime() {
+        return mVerificationTime;
+    }
+
+    /**
+     * A Hash-based message authentication code used to verify the contents and authenticity of the
+     * rest of the token. The hash is created using a secret key known only to the system server.
+     * When verifying the token, the system re-hashes the token and verifies the generated HMAC is
+     * the same.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @NonNull byte[] getHmac() {
+        return mHmac;
+    }
+
+    /**
+     * The UID of the process which called {@code verifyAttestation} to create the token, as
+     * returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
+     * of calling process does not match this value. This ensures that tokens cannot be shared
+     * between UIDs.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public int getUid() {
+        return mUid;
+    }
+
+    @DataClass.Generated.Member
+    static Parcelling<java.time.Instant> sParcellingForVerificationTime =
+            Parcelling.Cache.get(
+                    ForInstant.class);
+    static {
+        if (sParcellingForVerificationTime == null) {
+            sParcellingForVerificationTime = Parcelling.Cache.put(
+                    new ForInstant());
+        }
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mAttestationProfile, flags);
+        dest.writeInt(mLocalBindingType);
+        dest.writeBundle(mRequirements);
+        dest.writeInt(mVerificationResult);
+        sParcellingForVerificationTime.parcel(mVerificationTime, dest, flags);
+        dest.writeByteArray(mHmac);
+        dest.writeInt(mUid);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ VerificationToken(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        AttestationProfile attestationProfile = (AttestationProfile) in.readTypedObject(AttestationProfile.CREATOR);
+        int localBindingType = in.readInt();
+        Bundle requirements = in.readBundle();
+        int verificationResult = in.readInt();
+        java.time.Instant verificationTime = sParcellingForVerificationTime.unparcel(in);
+        byte[] hmac = in.createByteArray();
+        int uid = in.readInt();
+
+        this.mAttestationProfile = attestationProfile;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAttestationProfile);
+        this.mLocalBindingType = localBindingType;
+        com.android.internal.util.AnnotationValidations.validate(
+                LocalBindingType.class, null, mLocalBindingType);
+        this.mRequirements = requirements;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mRequirements);
+        this.mVerificationResult = verificationResult;
+        com.android.internal.util.AnnotationValidations.validate(
+                VerificationResult.class, null, mVerificationResult);
+        this.mVerificationTime = verificationTime;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mVerificationTime);
+        this.mHmac = hmac;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHmac);
+        this.mUid = uid;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<VerificationToken> CREATOR
+            = new Parcelable.Creator<VerificationToken>() {
+        @Override
+        public VerificationToken[] newArray(int size) {
+            return new VerificationToken[size];
+        }
+
+        @Override
+        public VerificationToken createFromParcel(@NonNull android.os.Parcel in) {
+            return new VerificationToken(in);
+        }
+    };
+
+    /**
+     * A builder for {@link VerificationToken}
+     * @hide
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @NonNull AttestationProfile mAttestationProfile;
+        private @LocalBindingType int mLocalBindingType;
+        private @NonNull Bundle mRequirements;
+        private @VerificationResult int mVerificationResult;
+        private @NonNull java.time.Instant mVerificationTime;
+        private @NonNull byte[] mHmac;
+        private int mUid;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param attestationProfile
+         *   The attestation profile which was used to perform the verification.
+         * @param localBindingType
+         *   The local binding type of the local binding data used to perform the verification.
+         * @param requirements
+         *   The requirements used to perform the verification.
+         * @param verificationResult
+         *   The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
+         *   byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
+         *   accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
+         *   value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
+         *   Duration)} to verify a valid token and it will return this value.
+         *
+         *   If the token is valid, this value is returned directly by {#verifyToken}.
+         * @param verificationTime
+         *   Time when the token was generated, set by the system.
+         * @param hmac
+         *   A Hash-based message authentication code used to verify the contents and authenticity of the
+         *   rest of the token. The hash is created using a secret key known only to the system server.
+         *   When verifying the token, the system re-hashes the token and verifies the generated HMAC is
+         *   the same.
+         * @param uid
+         *   The UID of the process which called {@code verifyAttestation} to create the token, as
+         *   returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
+         *   of calling process does not match this value. This ensures that tokens cannot be shared
+         *   between UIDs.
+         */
+        public Builder(
+                @NonNull AttestationProfile attestationProfile,
+                @LocalBindingType int localBindingType,
+                @NonNull Bundle requirements,
+                @VerificationResult int verificationResult,
+                @NonNull java.time.Instant verificationTime,
+                @NonNull byte[] hmac,
+                int uid) {
+            mAttestationProfile = attestationProfile;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mAttestationProfile);
+            mLocalBindingType = localBindingType;
+            com.android.internal.util.AnnotationValidations.validate(
+                    LocalBindingType.class, null, mLocalBindingType);
+            mRequirements = requirements;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mRequirements);
+            mVerificationResult = verificationResult;
+            com.android.internal.util.AnnotationValidations.validate(
+                    VerificationResult.class, null, mVerificationResult);
+            mVerificationTime = verificationTime;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mVerificationTime);
+            mHmac = hmac;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mHmac);
+            mUid = uid;
+        }
+
+        /**
+         * The attestation profile which was used to perform the verification.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setAttestationProfile(@NonNull AttestationProfile value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mAttestationProfile = value;
+            return this;
+        }
+
+        /**
+         * The local binding type of the local binding data used to perform the verification.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setLocalBindingType(@LocalBindingType int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mLocalBindingType = value;
+            return this;
+        }
+
+        /**
+         * The requirements used to perform the verification.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setRequirements(@NonNull Bundle value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mRequirements = value;
+            return this;
+        }
+
+        /**
+         * The result of the {@link AttestationVerificationManager#verifyAttestation(int, int, Bundle,
+         * byte[], Executor, BiConsumer)} call. This value is kept hidden to prevent token holders from
+         * accidentally reading this value without calling {@code verifyToken}. Do <b>not</b> use this
+         * value directly; call {@link AttestationVerificationManager#verifyToken(VerificationToken,
+         * Duration)} to verify a valid token and it will return this value.
+         *
+         * If the token is valid, this value is returned directly by {#verifyToken}.
+         *
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setVerificationResult(@VerificationResult int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mVerificationResult = value;
+            return this;
+        }
+
+        /**
+         * Time when the token was generated, set by the system.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setVerificationTime(@NonNull java.time.Instant value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10;
+            mVerificationTime = value;
+            return this;
+        }
+
+        /**
+         * A Hash-based message authentication code used to verify the contents and authenticity of the
+         * rest of the token. The hash is created using a secret key known only to the system server.
+         * When verifying the token, the system re-hashes the token and verifies the generated HMAC is
+         * the same.
+         *
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setHmac(@NonNull byte... value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mHmac = value;
+            return this;
+        }
+
+        /**
+         * The UID of the process which called {@code verifyAttestation} to create the token, as
+         * returned by {@link Binder#getCallingUid()}. Calls to {@code verifyToken} will fail if the UID
+         * of calling process does not match this value. This ensures that tokens cannot be shared
+         * between UIDs.
+         *
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setUid(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40;
+            mUid = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull VerificationToken build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x80; // Mark builder used
+
+            VerificationToken o = new VerificationToken(
+                    mAttestationProfile,
+                    mLocalBindingType,
+                    mRequirements,
+                    mVerificationResult,
+                    mVerificationTime,
+                    mHmac,
+                    mUid);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x80) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1633629747234L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/security/attestationverification/VerificationToken.java",
+            inputSignatures = "private final @android.annotation.NonNull android.security.attestationverification.AttestationProfile mAttestationProfile\nprivate final @android.security.attestationverification.AttestationVerificationManager.LocalBindingType int mLocalBindingType\nprivate final @android.annotation.NonNull android.os.Bundle mRequirements\nprivate final  @android.security.attestationverification.AttestationVerificationManager.VerificationResult int mVerificationResult\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) java.time.Instant mVerificationTime\nprivate final @android.annotation.NonNull byte[] mHmac\nprivate  int mUid\nclass VerificationToken extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genHiddenBuilder=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/security/attestationverification/package.html b/core/java/android/security/attestationverification/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/android/security/attestationverification/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index ece6b35..bab2089 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -242,35 +242,49 @@
      *
      * @hide
      */
-    public static String flagsToString(Class<?> clazz, String prefix, int flags) {
+    public static String flagsToString(Class<?> clazz, String prefix, long flags) {
         final StringBuilder res = new StringBuilder();
         boolean flagsWasZero = flags == 0;
 
         for (Field field : clazz.getDeclaredFields()) {
             final int modifiers = field.getModifiers();
             if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
-                    && field.getType().equals(int.class) && field.getName().startsWith(prefix)) {
-                try {
-                    final int value = field.getInt(null);
-                    if (value == 0 && flagsWasZero) {
-                        return constNameWithoutPrefix(prefix, field);
-                    }
-                    if (value != 0 && (flags & value) == value) {
-                        flags &= ~value;
-                        res.append(constNameWithoutPrefix(prefix, field)).append('|');
-                    }
-                } catch (IllegalAccessException ignored) {
+                    && (field.getType().equals(int.class) || field.getType().equals(long.class))
+                    && field.getName().startsWith(prefix)) {
+                final long value = getFieldValue(field);
+                if (value == 0 && flagsWasZero) {
+                    return constNameWithoutPrefix(prefix, field);
+                }
+                if (value != 0 && (flags & value) == value) {
+                    flags &= ~value;
+                    res.append(constNameWithoutPrefix(prefix, field)).append('|');
                 }
             }
         }
         if (flags != 0 || res.length() == 0) {
-            res.append(Integer.toHexString(flags));
+            res.append(Long.toHexString(flags));
         } else {
             res.deleteCharAt(res.length() - 1);
         }
         return res.toString();
     }
 
+    private static long getFieldValue(Field field) {
+        // Field could be int or long
+        try {
+            final long longValue = field.getLong(null);
+            if (longValue != 0) {
+                return longValue;
+            }
+            final int intValue = field.getInt(null);
+            if (intValue != 0) {
+                return intValue;
+            }
+        } catch (IllegalAccessException ignored) {
+        }
+        return 0;
+    }
+
     /**
      * Gets human-readable representation of constants (static final values).
      *
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index aa1acc1..a6f88a7 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -709,8 +709,8 @@
     }
 
     /**
-     * Queries the framework about whether any physical keys exist on the
-     * any keyboard attached to the device that are capable of producing the given key code.
+     * Queries the framework about whether any physical keys exist on any currently attached input
+     * devices that are capable of producing the given key code.
      *
      * @param keyCode The key code to query.
      * @return True if at least one attached keyboard supports the specified key code.
@@ -720,9 +720,8 @@
     }
 
     /**
-     * Queries the framework about whether any physical keys exist on the
-     * any keyboard attached to the device that are capable of producing the given
-     * array of key codes.
+     * Queries the framework about whether any physical keys exist on any currently attached input
+     * devices that are capable of producing the given array of key codes.
      *
      * @param keyCodes The array of key codes to query.
      * @return A new array of the same size as the key codes array whose elements
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7af77ca..00754af 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -613,7 +613,10 @@
         // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything.
         // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only
         // dump the summary information
-        int flags = (args == null || args.length == 0) ? FLAG_DUMP_ALL : 0;
+        if (args == null || args.length == 0) {
+            return FLAG_DUMP_ALL;
+        }
+        int flags = 0;
         for (int i = 0; i < args.length; i++) {
             switch (args[i]) {
                 case "framestats":
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
index ddf68fc..67d9667 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
@@ -38,9 +38,14 @@
      *                or {@link Float#NaN} to leave unchanged.
      * @param centerY the screen-relative Y coordinate around which to center,
      *                or {@link Float#NaN} to leave unchanged.
+     * @param magnificationFrameOffsetRatioX Indicate the X coordinate offset between
+     *                                       frame position X and centerX
+     * @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset between
+     *                                       frame position Y and centerY
      * @param callback The callback called when the animation is completed or interrupted.
      */
     void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+        float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
         in IRemoteMagnificationAnimationCallback callback);
 
     /**
diff --git a/core/java/android/widget/RemoteViewsListAdapter.java b/core/java/android/widget/RemoteViewsListAdapter.java
index 827d033..46f80f3 100644
--- a/core/java/android/widget/RemoteViewsListAdapter.java
+++ b/core/java/android/widget/RemoteViewsListAdapter.java
@@ -89,8 +89,7 @@
             RemoteViews rv = mRemoteViewsList.get(position);
             rv.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD);
             View v;
-            if (convertView != null && rv != null &&
-                    convertView.getId() == rv.getLayoutId()) {
+            if (convertView != null && convertView.getId() == rv.getLayoutId()) {
                 v = convertView;
                 rv.reapply(mContext, v, null /* handler */, null /* size */, mColorResources);
             } else {
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index bff813e..6a6f60e 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -512,6 +512,11 @@
      */
     public static final String DEFAULT_QR_CODE_SCANNER = "default_qr_code_scanner";
 
+    /**
+     * (boolean) Whether the task manager entrypoint is enabled.
+     */
+    public static final String TASK_MANAGER_ENABLED = "task_manager_enabled";
+
     private SystemUiDeviceConfigFlags() {
     }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 06d68e0..3aac0b1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3522,6 +3522,10 @@
      * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code>
      */
     private int writeHistoryTag(HistoryTag tag) {
+        if (tag.string == null) {
+            Slog.wtfStack(TAG, "writeHistoryTag called with null name");
+        }
+
         Integer idxObj = mHistoryTagPool.get(tag);
         int idx;
         if (idxObj != null) {
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 1ab316d..3147c34 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -23,6 +23,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -306,5 +307,33 @@
                 return string == null ? null : UUID.fromString(string);
             }
         }
+
+        /**
+         * A {@link Parcelling} for {@link Instant}.
+         *
+         * The minimum value of an instant uses a millisecond offset of about -3.15e19 which is
+         * larger than Long.MIN_VALUE, so we can use Long.MIN_VALUE as a sentinel value to indicate
+         * a null Instant.
+         */
+        class ForInstant implements Parcelling<Instant> {
+
+            @Override
+            public void parcel(Instant item, Parcel dest, int parcelFlags) {
+                dest.writeLong(item == null ? Long.MIN_VALUE : item.getEpochSecond());
+                dest.writeInt(item == null ? Integer.MIN_VALUE : item.getNano());
+            }
+
+            @Override
+            public Instant unparcel(Parcel source) {
+                long epochSecond = source.readLong();
+                int afterNano = source.readInt();
+
+                if (epochSecond == Long.MIN_VALUE) {
+                    return null;
+                } else {
+                    return Instant.ofEpochSecond(epochSecond, afterNano);
+                }
+            }
+        }
     }
 }
diff --git a/core/proto/android/app/location_time_zone_manager.proto b/core/proto/android/app/location_time_zone_manager.proto
index 891e9fc..5fdcfdf 100644
--- a/core/proto/android/app/location_time_zone_manager.proto
+++ b/core/proto/android/app/location_time_zone_manager.proto
@@ -23,6 +23,19 @@
 option java_multiple_files = true;
 option java_outer_classname = "LocationTimeZoneManagerProto";
 
+// A state enum that matches states for LocationTimeZoneProviderController. See that class for
+// details.
+enum ControllerStateEnum {
+  CONTROLLER_STATE_UNKNOWN = 0;
+  CONTROLLER_STATE_PROVIDERS_INITIALIZING = 1;
+  CONTROLLER_STATE_STOPPED = 2;
+  CONTROLLER_STATE_INITIALIZING = 3;
+  CONTROLLER_STATE_UNCERTAIN = 4;
+  CONTROLLER_STATE_CERTAIN = 5;
+  CONTROLLER_STATE_FAILED = 6;
+  CONTROLLER_STATE_DESTROYED = 7;
+}
+
 // Represents the state of the LocationTimeZoneManagerService for use in tests.
 message LocationTimeZoneManagerServiceStateProto {
   option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -30,6 +43,7 @@
   optional GeolocationTimeZoneSuggestionProto last_suggestion = 1;
   repeated TimeZoneProviderStateProto primary_provider_states = 2;
   repeated TimeZoneProviderStateProto secondary_provider_states = 3;
+  repeated ControllerStateEnum controller_states = 4;
 }
 
 // The state tracked for a LocationTimeZoneProvider.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d926f98..85ae7a1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1840,11 +1840,11 @@
     <permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows applications to act as network scorers. @hide @SystemApi-->
+    <!-- @deprecated Allows applications to act as network scorers. @hide @SystemApi-->
     <permission android:name="android.permission.SCORE_NETWORKS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows applications to request network
+    <!-- @deprecated Allows applications to request network
          recommendations and scores from the NetworkScoreService.
          @SystemApi
          <p>Not for use by third-party applications. @hide -->
@@ -3470,6 +3470,23 @@
     <permission android:name="android.permission.UPDATE_FONTS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to use the AttestationVerificationService.
+         @hide -->
+    <permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE"
+                android:protectionLevel="signature" />
+
+    <!-- Allows an application to export a AttestationVerificationService to verify attestations on
+         behalf of AttestationVerificationManager for system-defined attestation profiles.
+         @hide -->
+    <permission android:name="android.permission.VERIFY_ATTESTATION"
+                android:protectionLevel="signature" />
+
+    <!-- Must be required by any AttestationVerificationService to ensure that only the system can
+         bind to it.
+         @hide -->
+    <permission android:name="android.permission.BIND_ATTESTATION_VERIFICATION_SERVICE"
+                android:protectionLevel="signature" />
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
diff --git a/core/res/res/layout-watch/preference_list_fragment_material.xml b/core/res/res/layout-watch/preference_list_fragment_material.xml
index 22e66d5..8f2658b 100644
--- a/core/res/res/layout-watch/preference_list_fragment_material.xml
+++ b/core/res/res/layout-watch/preference_list_fragment_material.xml
@@ -43,7 +43,7 @@
                 android:paddingStart="@dimen/dialog_padding_material"
                 android:paddingEnd="@dimen/dialog_padding_material"
                 android:paddingBottom="8dp"
-                android:textAppearance="@style/TextAppearance.Material.Title"
+                android:textAppearance="?android:attr/textAppearanceLarge"
                 android:gravity="center_horizontal|top" />
         </com.android.internal.widget.WatchHeaderListView>
     </FrameLayout>
diff --git a/core/tests/coretests/src/android/os/CombinedVibrationTest.java b/core/tests/coretests/src/android/os/CombinedVibrationTest.java
index 06b5d18..508856b 100644
--- a/core/tests/coretests/src/android/os/CombinedVibrationTest.java
+++ b/core/tests/coretests/src/android/os/CombinedVibrationTest.java
@@ -125,6 +125,12 @@
                 VibrationEffect.createOneShot(1, 1)).getDuration());
         assertEquals(-1, CombinedVibration.createParallel(
                 VibrationEffect.get(VibrationEffect.EFFECT_CLICK)).getDuration());
+        assertEquals(-1, CombinedVibration.createParallel(
+                        VibrationEffect.startComposition()
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 100)
+                                .compose())
+                .getDuration());
         assertEquals(Long.MAX_VALUE, CombinedVibration.createParallel(
                 VibrationEffect.createWaveform(
                         new long[]{1, 2, 3}, new int[]{1, 2, 3}, 0)).getDuration());
@@ -175,6 +181,83 @@
     }
 
     @Test
+    public void testIsHapticFeedbackCandidateMono() {
+        assertTrue(CombinedVibration.createParallel(
+                VibrationEffect.createOneShot(1, 1)).isHapticFeedbackCandidate());
+        assertTrue(CombinedVibration.createParallel(
+                VibrationEffect.get(VibrationEffect.EFFECT_CLICK)).isHapticFeedbackCandidate());
+        assertTrue(CombinedVibration.createParallel(
+                        VibrationEffect.startComposition()
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 100)
+                                .compose())
+                .isHapticFeedbackCandidate());
+        // Too long to be classified as a haptic feedback.
+        assertFalse(CombinedVibration.createParallel(
+                VibrationEffect.createOneShot(10_000, 1)).isHapticFeedbackCandidate());
+        // Repeating vibrations should not be classified as a haptic feedback.
+        assertFalse(CombinedVibration.createParallel(
+                VibrationEffect.createWaveform(new long[]{1}, new int[]{1}, 0))
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidateStereo() {
+        assertTrue(CombinedVibration.startParallel()
+                .addVibrator(1, VibrationEffect.createOneShot(1, 1))
+                .addVibrator(2, VibrationEffect.createWaveform(new long[]{6}, new int[]{1}, -1))
+                .combine()
+                .isHapticFeedbackCandidate());
+        assertTrue(CombinedVibration.startParallel()
+                .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .addVibrator(2,
+                        VibrationEffect.startComposition()
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 100)
+                                .compose())
+                .combine()
+                .isHapticFeedbackCandidate());
+        // Repeating vibrations should not be classified as a haptic feedback.
+        assertFalse(CombinedVibration.startParallel()
+                .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .addVibrator(2, VibrationEffect.createWaveform(new long[]{1}, new int[]{1}, 0))
+                .combine()
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidateSequential() {
+        assertTrue(CombinedVibration.startSequential()
+                .addNext(1, VibrationEffect.createOneShot(10, 10), 10)
+                .addNext(2, VibrationEffect.createWaveform(new long[]{5}, new int[]{1}, -1))
+                .combine()
+                .isHapticFeedbackCandidate());
+        assertTrue(CombinedVibration.startSequential()
+                .addNext(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .addNext(2,
+                        VibrationEffect.startComposition()
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE)
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL)
+                                .compose())
+                .combine()
+                .isHapticFeedbackCandidate());
+        // Repeating vibrations should not be classified as a haptic feedback.
+        assertFalse(CombinedVibration.startSequential()
+                .addNext(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .addNext(2, VibrationEffect.createWaveform(new long[]{1}, new int[]{1}, 0))
+                .combine()
+                .isHapticFeedbackCandidate());
+        // Too many effects to be classified as a haptic feedback.
+        assertFalse(CombinedVibration.startSequential()
+                .addNext(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .addNext(2, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
+                .addNext(3, VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK))
+                .addNext(1, VibrationEffect.get(VibrationEffect.EFFECT_THUD))
+                .combine()
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
     public void testHasVibratorMono_returnsTrueForAnyVibrator() {
         CombinedVibration effect = CombinedVibration.createParallel(
                 VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
diff --git a/core/tests/coretests/src/android/os/VibrationEffectTest.java b/core/tests/coretests/src/android/os/VibrationEffectTest.java
index 6cbfffc..781564b 100644
--- a/core/tests/coretests/src/android/os/VibrationEffectTest.java
+++ b/core/tests/coretests/src/android/os/VibrationEffectTest.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
@@ -312,8 +313,106 @@
         assertTrue(100 / 255f > ((StepSegment) scaledDown.getSegments().get(1)).getAmplitude());
     }
 
+
+    @Test
+    public void testDuration() {
+        assertEquals(1, VibrationEffect.createOneShot(1, 1).getDuration());
+        assertEquals(-1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK).getDuration());
+        assertEquals(-1,
+                VibrationEffect.startComposition()
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 100)
+                        .compose()
+                        .getDuration());
+        assertEquals(6, VibrationEffect.createWaveform(
+                new long[]{1, 2, 3}, new int[]{1, 2, 3}, -1).getDuration());
+        assertEquals(Long.MAX_VALUE, VibrationEffect.createWaveform(
+                new long[]{1, 2, 3}, new int[]{1, 2, 3}, 0).getDuration());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_repeatingEffects_notCandidates() {
+        assertFalse(VibrationEffect.createWaveform(
+                new long[]{1, 2, 3}, new int[]{1, 2, 3}, 0).isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_longEffects_notCandidates() {
+        assertFalse(VibrationEffect.createOneShot(1500, 255).isHapticFeedbackCandidate());
+        assertFalse(VibrationEffect.createWaveform(
+                new long[]{200, 200, 700}, new int[]{1, 2, 3}, -1).isHapticFeedbackCandidate());
+        assertFalse(VibrationEffect.startWaveform()
+                .addRamp(1, 500)
+                .addStep(1, 200)
+                .addRamp(0, 500)
+                .build()
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_shortEffects_areCandidates() {
+        assertTrue(VibrationEffect.createOneShot(500, 255).isHapticFeedbackCandidate());
+        assertTrue(VibrationEffect.createWaveform(
+                new long[]{100, 200, 300}, new int[]{1, 2, 3}, -1).isHapticFeedbackCandidate());
+        assertTrue(VibrationEffect.startWaveform()
+                .addRamp(1, 300)
+                .addStep(1, 200)
+                .addRamp(0, 300)
+                .build()
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_longCompositions_notCandidates() {
+        assertFalse(VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_THUD)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL)
+                .compose()
+                .isHapticFeedbackCandidate());
+
+        assertFalse(VibrationEffect.startComposition()
+                .addEffect(VibrationEffect.createOneShot(1500, 255))
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                .compose()
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_shortCompositions_areCandidates() {
+        assertTrue(VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                .compose()
+                .isHapticFeedbackCandidate());
+
+        assertTrue(VibrationEffect.startComposition()
+                .addEffect(VibrationEffect.createOneShot(100, 255))
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                .compose()
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_prebakedRingtones_notCandidates() {
+        assertFalse(VibrationEffect.get(
+                VibrationEffect.RINGTONES[1]).isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_prebakedNotRingtoneConstants_areCandidates() {
+        assertTrue(VibrationEffect.get(VibrationEffect.EFFECT_CLICK).isHapticFeedbackCandidate());
+        assertTrue(VibrationEffect.get(VibrationEffect.EFFECT_THUD).isHapticFeedbackCandidate());
+        assertTrue(VibrationEffect.get(VibrationEffect.EFFECT_TICK).isHapticFeedbackCandidate());
+    }
+
     private Resources mockRingtoneResources() {
-        return mockRingtoneResources(new String[] {
+        return mockRingtoneResources(new String[]{
                 RINGTONE_URI_1,
                 RINGTONE_URI_2,
                 RINGTONE_URI_3
diff --git a/core/tests/coretests/src/android/os/VibratorTest.java b/core/tests/coretests/src/android/os/VibratorTest.java
index 6b69b3f..bdd76a5 100644
--- a/core/tests/coretests/src/android/os/VibratorTest.java
+++ b/core/tests/coretests/src/android/os/VibratorTest.java
@@ -250,17 +250,4 @@
         VibrationAttributes vibrationAttributes = captor.getValue();
         assertEquals(new VibrationAttributes.Builder().build(), vibrationAttributes);
     }
-
-    @Test
-    public void vibrate_withoutAudioAttributesAndLongEffect_hasUnknownUsage() {
-        mVibratorSpy.vibrate(VibrationEffect.createOneShot(10_000, 255));
-
-        ArgumentCaptor<VibrationAttributes> captor = ArgumentCaptor.forClass(
-                VibrationAttributes.class);
-        verify(mVibratorSpy).vibrate(anyInt(), anyString(), any(), isNull(), captor.capture());
-
-        VibrationAttributes vibrationAttributes = captor.getValue();
-        assertEquals(VibrationAttributes.USAGE_UNKNOWN, vibrationAttributes.getUsage());
-        assertEquals(AudioAttributes.USAGE_UNKNOWN, vibrationAttributes.getAudioUsage());
-    }
 }
diff --git a/core/tests/coretests/src/android/os/vibrator/PrebakedSegmentTest.java b/core/tests/coretests/src/android/os/vibrator/PrebakedSegmentTest.java
index de80812..a0e1f43 100644
--- a/core/tests/coretests/src/android/os/vibrator/PrebakedSegmentTest.java
+++ b/core/tests/coretests/src/android/os/vibrator/PrebakedSegmentTest.java
@@ -17,6 +17,7 @@
 package android.os.vibrator;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertSame;
 import static junit.framework.Assert.assertTrue;
 
@@ -105,4 +106,49 @@
                 VibrationEffect.EFFECT_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
         assertSame(prebaked, prebaked.scale(0.5f));
     }
+
+    @Test
+    public void testDuration() {
+        assertEquals(-1, new PrebakedSegment(
+                VibrationEffect.EFFECT_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .getDuration());
+        assertEquals(-1, new PrebakedSegment(
+                VibrationEffect.EFFECT_TICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .getDuration());
+        assertEquals(-1, new PrebakedSegment(
+                VibrationEffect.EFFECT_DOUBLE_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .getDuration());
+        assertEquals(-1, new PrebakedSegment(
+                VibrationEffect.EFFECT_THUD, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .getDuration());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_prebakedConstants_areCandidates() {
+        assertTrue(new PrebakedSegment(
+                VibrationEffect.EFFECT_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .isHapticFeedbackCandidate());
+        assertTrue(new PrebakedSegment(
+                VibrationEffect.EFFECT_TICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .isHapticFeedbackCandidate());
+        assertTrue(new PrebakedSegment(
+                VibrationEffect.EFFECT_DOUBLE_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .isHapticFeedbackCandidate());
+        assertTrue(new PrebakedSegment(
+                VibrationEffect.EFFECT_HEAVY_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .isHapticFeedbackCandidate());
+        assertTrue(new PrebakedSegment(
+                VibrationEffect.EFFECT_THUD, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .isHapticFeedbackCandidate());
+        assertTrue(new PrebakedSegment(
+                VibrationEffect.EFFECT_TEXTURE_TICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .isHapticFeedbackCandidate());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_prebakedRingtones_notCandidates() {
+        assertFalse(new PrebakedSegment(
+                VibrationEffect.RINGTONES[1], true, VibrationEffect.EFFECT_STRENGTH_MEDIUM)
+                .isHapticFeedbackCandidate());
+    }
 }
diff --git a/core/tests/coretests/src/android/os/vibrator/PrimitiveSegmentTest.java b/core/tests/coretests/src/android/os/vibrator/PrimitiveSegmentTest.java
index 538655b..a690553 100644
--- a/core/tests/coretests/src/android/os/vibrator/PrimitiveSegmentTest.java
+++ b/core/tests/coretests/src/android/os/vibrator/PrimitiveSegmentTest.java
@@ -127,4 +127,28 @@
         assertEquals(0f, initial.scale(1.5f).scale(2 / 3f).getScale(), TOLERANCE);
         assertEquals(0f, initial.scale(0.8f).scale(1.25f).getScale(), TOLERANCE);
     }
+
+    @Test
+    public void testDuration() {
+        assertEquals(-1, new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_NOOP, 1, 10).getDuration());
+        assertEquals(-1, new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 100).getDuration());
+        assertEquals(-1, new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_SPIN, 1, 0).getDuration());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_returnsTrue() {
+        assertTrue(new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_NOOP, 1, 10).isHapticFeedbackCandidate());
+        assertTrue(new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 10).isHapticFeedbackCandidate());
+        assertTrue(new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10).isHapticFeedbackCandidate());
+        assertTrue(new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_THUD, 1, 10).isHapticFeedbackCandidate());
+        assertTrue(new PrimitiveSegment(
+                VibrationEffect.Composition.PRIMITIVE_SPIN, 1, 10).isHapticFeedbackCandidate());
+    }
 }
diff --git a/core/tests/coretests/src/android/os/vibrator/RampSegmentTest.java b/core/tests/coretests/src/android/os/vibrator/RampSegmentTest.java
index 174b4a7..5f80d2a 100644
--- a/core/tests/coretests/src/android/os/vibrator/RampSegmentTest.java
+++ b/core/tests/coretests/src/android/os/vibrator/RampSegmentTest.java
@@ -125,4 +125,16 @@
         assertEquals(0.35f, initial.scale(0.8f).getStartAmplitude(), TOLERANCE);
         assertEquals(0.5f, initial.scale(0.8f).scale(1.25f).getStartAmplitude(), TOLERANCE);
     }
+
+    @Test
+    public void testDuration() {
+        assertEquals(10, new RampSegment(0.5f, 1, 0, 0, 10).getDuration());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_returnsTrue() {
+        // A single ramp segment duration is not checked here, but contributes to the effect known
+        // duration checked in VibrationEffect implementations.
+        assertTrue(new RampSegment(0.5f, 1, 0, 0, 5_000).isHapticFeedbackCandidate());
+    }
 }
diff --git a/core/tests/coretests/src/android/os/vibrator/StepSegmentTest.java b/core/tests/coretests/src/android/os/vibrator/StepSegmentTest.java
index 79529b8..fdce86a 100644
--- a/core/tests/coretests/src/android/os/vibrator/StepSegmentTest.java
+++ b/core/tests/coretests/src/android/os/vibrator/StepSegmentTest.java
@@ -141,4 +141,16 @@
         assertEquals(VibrationEffect.DEFAULT_AMPLITUDE, initial.scale(1.5f).getAmplitude(),
                 TOLERANCE);
     }
+
+    @Test
+    public void testDuration() {
+        assertEquals(5, new StepSegment(0, 0, 5).getDuration());
+    }
+
+    @Test
+    public void testIsHapticFeedbackCandidate_returnsTrue() {
+        // A single step segment duration is not checked here, but contributes to the effect known
+        // duration checked in VibrationEffect implementations.
+        assertTrue(new StepSegment(0, 0, 5_000).isHapticFeedbackCandidate());
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 7354c90..b843589 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -79,7 +79,7 @@
  * mask using {@code setId(..., android.R.id.mask)} or an existing mask layer
  * may be replaced using {@code setDrawableByLayerId(android.R.id.mask, ...)}.
  * <pre>
- * <code>&lt;!-- A red ripple masked against an opaque rectangle. --/>
+ * <code>&lt;!-- A red ripple masked against an opaque rectangle. -->
  * &lt;ripple android:color="#ffff0000">
  *   &lt;item android:id="@android:id/mask"
  *         android:drawable="@android:color/white" />
@@ -92,12 +92,12 @@
  * If no mask layer is set, the ripple effect is masked against the composite
  * of the child layers.
  * <pre>
- * <code>&lt;!-- A green ripple drawn atop a black rectangle. --/>
+ * <code>&lt;!-- A green ripple drawn atop a black rectangle. -->
  * &lt;ripple android:color="#ff00ff00">
  *   &lt;item android:drawable="@android:color/black" />
  * &lt;/ripple>
  *
- * &lt;!-- A blue ripple drawn atop a drawable resource. --/>
+ * &lt;!-- A blue ripple drawn atop a drawable resource. -->
  * &lt;ripple android:color="#ff0000ff">
  *   &lt;item android:drawable="@drawable/my_drawable" />
  * &lt;/ripple></code>
@@ -108,7 +108,7 @@
  * background within the View's hierarchy. In this case, the drawing region
  * may extend outside of the Drawable bounds.
  * <pre>
- * <code>&lt;!-- An unbounded red ripple. --/>
+ * <code>&lt;!-- An unbounded red ripple. -->
  * &lt;ripple android:color="#ffff0000" /></code>
  * </pre>
  *
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index df5b3f5..a34d0ab 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -287,7 +287,7 @@
          *
          * @param computeHyphenation true if you want to use automatic hyphenations.
          */
-        public @NonNull Builder setComputeHyphenation(boolean computeHyphenation) {
+        public @NonNull @Deprecated Builder setComputeHyphenation(boolean computeHyphenation) {
             setComputeHyphenation(
                     computeHyphenation ? HYPHENATION_MODE_NORMAL : HYPHENATION_MODE_NONE);
             return this;
@@ -331,8 +331,6 @@
          *
          * {@link #HYPHENATION_MODE_NONE} is by default.
          *
-         * @see #setComputeHyphenation(boolean)
-         *
          * @param mode a hyphenation mode.
          */
         public @NonNull Builder setComputeHyphenation(@HyphenationMode int mode) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 7f37036..8e98b82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -216,6 +216,14 @@
         }
     }
 
+    @Override
+    public void unregisterOrganizer() {
+        super.unregisterOrganizer();
+        if (mStartingWindow != null) {
+            mStartingWindow.clearAllWindows();
+        }
+    }
+
     public void createRootTask(int displayId, int windowingMode, TaskListener listener) {
         ProtoLog.v(WM_SHELL_TASK_ORG, "createRootTask() displayId=%d winMode=%d listener=%s",
                 displayId, windowingMode, listener.toString());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index c2ebc30..854fc60e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1255,11 +1255,7 @@
         } else if (isOutPipDirection(direction)) {
             // If we are animating to fullscreen or split screen, then we need to reset the
             // override bounds on the task to ensure that the task "matches" the parent's bounds.
-            if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
-                taskBounds = destinationBounds;
-            } else {
-                taskBounds = null;
-            }
+            taskBounds = null;
             applyWindowingModeChangeOnExit(wct, direction);
         } else {
             // Just a resize in PIP
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 6280f76..a5579ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -781,6 +781,7 @@
             final WindowContainerTransaction wct = new WindowContainerTransaction();
             // Make the stages adjacent to each other so they occlude what's behind them.
             wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
+            wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
             mTaskOrganizer.applyTransaction(wct);
         }
     }
@@ -788,6 +789,7 @@
     private void onStageRootTaskVanished(StageListenerImpl stageListener) {
         if (stageListener == mMainStageListener || stageListener == mSideStageListener) {
             final WindowContainerTransaction wct = new WindowContainerTransaction();
+            wct.clearLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
             // Deactivate the main stage if it no longer has a root task.
             mMainStage.deactivate(wct);
             mTaskOrganizer.applyTransaction(wct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index a9c81b3..73f65b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -134,7 +134,8 @@
         mDisplayManager.getDisplay(DEFAULT_DISPLAY);
     }
 
-    private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
+    @VisibleForTesting
+    final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
 
     /**
      * Records of {@link SurfaceControlViewHost} where the splash screen icon animation is
@@ -459,8 +460,23 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
                 "Task start finish, remove starting surface for task: %d",
                 removalInfo.taskId);
-        removeWindowSynced(removalInfo);
+        removeWindowSynced(removalInfo, false /* immediately */);
+    }
 
+    /**
+     * Clear all starting windows immediately.
+     */
+    public void clearAllWindows() {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+                "Clear all starting windows immediately");
+        final int taskSize = mStartingWindowRecords.size();
+        final int[] taskIds = new int[taskSize];
+        for (int i = taskSize - 1; i >= 0; --i) {
+            taskIds[i] = mStartingWindowRecords.keyAt(i);
+        }
+        for (int i = taskSize - 1; i >= 0; --i) {
+            removeWindowNoAnimate(taskIds[i]);
+        }
     }
 
     /**
@@ -542,7 +558,8 @@
         return shouldSaveView;
     }
 
-    private void saveSplashScreenRecord(IBinder appToken, int taskId, View view,
+    @VisibleForTesting
+    void saveSplashScreenRecord(IBinder appToken, int taskId, View view,
             @StartingWindowType int suggestType) {
         final StartingWindowRecord tView = new StartingWindowRecord(appToken, view,
                 null/* TaskSnapshotWindow */, suggestType);
@@ -551,19 +568,18 @@
 
     private void removeWindowNoAnimate(int taskId) {
         mTmpRemovalInfo.taskId = taskId;
-        removeWindowSynced(mTmpRemovalInfo);
+        removeWindowSynced(mTmpRemovalInfo, true /* immediately */);
     }
 
     void onImeDrawnOnTask(int taskId) {
         final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
         if (record != null && record.mTaskSnapshotWindow != null
                 && record.mTaskSnapshotWindow.hasImeSurface()) {
-            record.mTaskSnapshotWindow.removeImmediately();
+            removeWindowNoAnimate(taskId);
         }
-        mStartingWindowRecords.remove(taskId);
     }
 
-    protected void removeWindowSynced(StartingWindowRemovalInfo removalInfo) {
+    protected void removeWindowSynced(StartingWindowRemovalInfo removalInfo, boolean immediately) {
         final int taskId = removalInfo.taskId;
         final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
         if (record != null) {
@@ -571,7 +587,8 @@
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
                         "Removing splash screen window for task: %d", taskId);
                 if (record.mContentView != null) {
-                    if (record.mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+                    if (immediately
+                            || record.mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
                         removeWindowInner(record.mDecorView, false);
                     } else {
                         if (removalInfo.playRevealAnimation) {
@@ -594,8 +611,12 @@
             if (record.mTaskSnapshotWindow != null) {
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
                         "Removing task snapshot window for %d", taskId);
-                record.mTaskSnapshotWindow.scheduleRemove(
-                        () -> mStartingWindowRecords.remove(taskId), removalInfo.deferRemoveForIme);
+                if (immediately) {
+                    record.mTaskSnapshotWindow.removeImmediately();
+                } else {
+                    record.mTaskSnapshotWindow.scheduleRemove(() ->
+                            mStartingWindowRecords.remove(taskId), removalInfo.deferRemoveForIme);
+                }
             }
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index b62360e..487eb70 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -194,6 +194,18 @@
     }
 
     /**
+     * Clear all starting window immediately, called this method when releasing the task organizer.
+     */
+    public void clearAllWindows() {
+        mSplashScreenExecutor.execute(() -> {
+            mStartingSurfaceDrawer.clearAllWindows();
+            synchronized (mTaskBackgroundColors) {
+                mTaskBackgroundColors.clear();
+            }
+        });
+    }
+
+    /**
      * The interface for calls from outside the Shell, within the host process.
      */
     private class StartingSurfaceImpl implements StartingSurface {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 70b7c67..d92b12e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -31,6 +31,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -117,16 +118,19 @@
                 WindowManager.LayoutParams params, int suggestType) {
             // listen for addView
             mAddWindowForTask = taskId;
+            saveSplashScreenRecord(appToken, taskId, view, suggestType);
             // Do not wait for background color
             return false;
         }
 
         @Override
-        protected void removeWindowSynced(StartingWindowRemovalInfo removalInfo) {
+        protected void removeWindowSynced(StartingWindowRemovalInfo removalInfo,
+                boolean immediately) {
             // listen for removeView
             if (mAddWindowForTask == removalInfo.taskId) {
                 mAddWindowForTask = 0;
             }
+            mStartingWindowRecords.remove(removalInfo.taskId);
         }
     }
 
@@ -179,7 +183,7 @@
         removalInfo.taskId = windowInfo.taskInfo.taskId;
         mStartingSurfaceDrawer.removeStartingWindow(removalInfo);
         waitHandlerIdle(mTestHandler);
-        verify(mStartingSurfaceDrawer).removeWindowSynced(any());
+        verify(mStartingSurfaceDrawer).removeWindowSynced(any(), eq(false));
         assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
     }
 
@@ -267,11 +271,32 @@
 
             // Verify the task snapshot with IME snapshot will be removed when received the real IME
             // drawn callback.
+            // makeTaskSnapshotWindow shall call removeWindowSynced before there add a new
+            // StartingWindowRecord for the task.
             mStartingSurfaceDrawer.onImeDrawnOnTask(1);
-            verify(mockSnapshotWindow).removeImmediately();
+            verify(mStartingSurfaceDrawer, times(2))
+                    .removeWindowSynced(any(), eq(true));
         }
     }
 
+    @Test
+    public void testClearAllWindows() {
+        final int taskId = 1;
+        final StartingWindowInfo windowInfo =
+                createWindowInfo(taskId, android.R.style.Theme);
+        mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder,
+                STARTING_WINDOW_TYPE_SPLASH_SCREEN);
+        waitHandlerIdle(mTestHandler);
+        verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(),
+                eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN));
+        assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
+
+        mStartingSurfaceDrawer.clearAllWindows();
+        waitHandlerIdle(mTestHandler);
+        verify(mStartingSurfaceDrawer).removeWindowSynced(any(), eq(true));
+        assertEquals(mStartingSurfaceDrawer.mStartingWindowRecords.size(), 0);
+    }
+
     private StartingWindowInfo createWindowInfo(int taskId, int themeResId) {
         StartingWindowInfo windowInfo = new StartingWindowInfo();
         final ActivityInfo info = new ActivityInfo();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
index b8ad321..0b436a9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.bluetooth;
 
+import android.annotation.SuppressLint;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothUuid;
@@ -118,8 +119,8 @@
                     return true;
                 }
             } else if (btClass != null) {
-                if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) ||
-                        btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+                if (doesClassMatch(btClass, BluetoothClass.PROFILE_A2DP)
+                        || doesClassMatch(btClass, BluetoothClass.PROFILE_HEADSET)) {
                     return true;
                 }
             }
@@ -137,7 +138,7 @@
                 }
             }
             return btClass != null
-                    && btClass.doesClassMatch(BluetoothClass.PROFILE_OPP);
+                    && doesClassMatch(btClass, BluetoothClass.PROFILE_OPP);
         }
     }
 
@@ -151,7 +152,7 @@
                 }
             }
             return btClass != null
-                    && btClass.doesClassMatch(BluetoothClass.PROFILE_PANU);
+                    && doesClassMatch(btClass, BluetoothClass.PROFILE_PANU);
         }
     }
 
@@ -165,7 +166,12 @@
                 }
             }
             return btClass != null
-                    && btClass.doesClassMatch(BluetoothClass.PROFILE_NAP);
+                    && doesClassMatch(btClass, BluetoothClass.PROFILE_NAP);
         }
     }
+
+    @SuppressLint("NewApi") // Hidden API made public
+    private static boolean doesClassMatch(BluetoothClass btClass, int classId) {
+        return btClass.doesClassMatch(classId);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 253629c..c9af4d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -2,6 +2,7 @@
 
 import static com.android.settingslib.widget.AdaptiveOutlineDrawable.ICON_TYPE_ADVANCED;
 
+import android.annotation.SuppressLint;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
@@ -70,6 +71,12 @@
         void onShowError(Context context, String name, int messageResId);
     }
 
+    /**
+     * @param context to access resources from
+     * @param cachedDevice to get class from
+     * @return pair containing the drawable and the description of the Bluetooth class
+     *         of the device.
+     */
     public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
             CachedBluetoothDevice cachedDevice) {
         BluetoothClass btClass = cachedDevice.getBtClass();
@@ -110,13 +117,13 @@
             }
         }
         if (btClass != null) {
-            if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+            if (doesClassMatch(btClass, BluetoothClass.PROFILE_HEADSET)) {
                 return new Pair<>(
                         getBluetoothDrawable(context,
                                 com.android.internal.R.drawable.ic_bt_headset_hfp),
                         context.getString(R.string.bluetooth_talkback_headset));
             }
-            if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
+            if (doesClassMatch(btClass, BluetoothClass.PROFILE_A2DP)) {
                 return new Pair<>(
                         getBluetoothDrawable(context,
                                 com.android.internal.R.drawable.ic_bt_headphones_a2dp),
@@ -376,4 +383,9 @@
         }
         return Uri.parse(data);
     }
+
+    @SuppressLint("NewApi") // Hidden API made public
+    private static boolean doesClassMatch(BluetoothClass btClass, int classId) {
+        return btClass.doesClassMatch(classId);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 9d4669a..cd5c78d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -62,7 +62,7 @@
         if (!(drawable instanceof BitmapDrawable)) {
             setColorFilter(drawable);
         }
-        return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
+        return drawable;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 949b245..c34f65c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -29,7 +29,6 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.R;
-import com.android.settingslib.bluetooth.BluetoothUtils;
 
 import java.util.List;
 
@@ -61,7 +60,7 @@
     public Drawable getIcon() {
         final Drawable drawable = getIconWithoutBackground();
         setColorFilter(drawable);
-        return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
+        return drawable;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index b6c0b30..1139d33 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -32,7 +32,6 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.R;
-import com.android.settingslib.bluetooth.BluetoothUtils;
 
 /**
  * PhoneMediaDevice extends MediaDevice to represents Phone device.
@@ -87,7 +86,7 @@
     public Drawable getIcon() {
         final Drawable drawable = getIconWithoutBackground();
         setColorFilter(drawable);
-        return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
+        return drawable;
     }
 
     @Override
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 8c70112..ee9d430 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -150,6 +150,7 @@
     // Internal intents used on notification actions.
     static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
     static final String INTENT_BUGREPORT_SHARE = "android.intent.action.BUGREPORT_SHARE";
+    static final String INTENT_BUGREPORT_DONE = "android.intent.action.BUGREPORT_DONE";
     static final String INTENT_BUGREPORT_INFO_LAUNCH =
             "android.intent.action.BUGREPORT_INFO_LAUNCH";
     static final String INTENT_BUGREPORT_SCREENSHOT =
@@ -555,6 +556,8 @@
                 case INTENT_BUGREPORT_SHARE:
                     shareBugreport(id, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
                     break;
+                case INTENT_BUGREPORT_DONE:
+                    maybeShowWarningMessageAndCloseNotification(id);
                 case INTENT_BUGREPORT_CANCEL:
                     cancel(id);
                     break;
@@ -809,10 +812,30 @@
     }
 
     /**
+     * Creates a {@link PendingIntent} for a notification action used to show warning about the
+     * sensitivity of bugreport data and then close bugreport notification.
+     *
+     * Note that, the warning message may not be shown if the user has chosen not to see the
+     * message anymore.
+     */
+    private static PendingIntent newBugreportDoneIntent(Context context, BugreportInfo info) {
+        final Intent intent = new Intent(INTENT_BUGREPORT_DONE);
+        intent.setClass(context, BugreportProgressService.class);
+        intent.putExtra(EXTRA_ID, info.id);
+        return PendingIntent.getService(context, info.id, intent,
+                PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
+    @GuardedBy("mLock")
+    private void stopProgressLocked(int id) {
+        stopProgressLocked(id, /* cancelNotification */ true);
+    }
+
+    /**
      * Finalizes the progress on a given bugreport and cancel its notification.
      */
     @GuardedBy("mLock")
-    private void stopProgressLocked(int id) {
+    private void stopProgressLocked(int id, boolean cancelNotification) {
         if (mBugreportInfos.indexOfKey(id) < 0) {
             Log.w(TAG, "ID not watched: " + id);
         } else {
@@ -821,8 +844,13 @@
         }
         // Must stop foreground service first, otherwise notif.cancel() will fail below.
         stopForegroundWhenDoneLocked(id);
-        Log.d(TAG, "stopProgress(" + id + "): cancel notification");
-        NotificationManager.from(mContext).cancel(id);
+
+        if (cancelNotification) {
+            Log.d(TAG, "stopProgress(" + id + "): cancel notification");
+            NotificationManager.from(mContext).cancel(id);
+        } else {
+            Log.d(TAG, "stopProgress(" + id + ")");
+        }
         stopSelfWhenDoneLocked();
     }
 
@@ -1039,7 +1067,8 @@
     }
 
     /**
-     * Wraps up bugreport generation and triggers a notification to share the bugreport.
+     * Wraps up bugreport generation and triggers a notification to either share the bugreport or
+     * just notify the ending of the bugreport generation, according to the device type.
      */
     private void onBugreportFinished(BugreportInfo info) {
         if (!TextUtils.isEmpty(info.shareTitle)) {
@@ -1054,25 +1083,46 @@
             stopForegroundWhenDoneLocked(info.id);
         }
 
-        triggerLocalNotification(mContext, info);
-    }
-
-    /**
-     * Responsible for triggering a notification that allows the user to start a "share" intent with
-     * the bugreport. On watches we have other methods to allow the user to start this intent
-     * (usually by triggering it on another connected device); we don't need to display the
-     * notification in this case.
-     */
-    private void triggerLocalNotification(final Context context, final BugreportInfo info) {
         if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
             Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
-            Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
+            Toast.makeText(mContext, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
             synchronized (mLock) {
                 stopProgressLocked(info.id);
             }
             return;
         }
 
+        if (mIsWatch) {
+            // Wear wants to send the notification directly and not wait for the user to tap on the
+            // notification.
+            triggerShareBugreportAndLocalNotification(info);
+        } else {
+            triggerLocalNotification(info);
+        }
+    }
+
+    /**
+     * Responsible for starting the bugerport sharing process and posting a notification which
+     * shows that the bugreport has been taken and that the sharing process has kicked-off.
+     */
+    private void triggerShareBugreportAndLocalNotification(final BugreportInfo info) {
+        boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
+        if (!isPlainText) {
+            // Already zipped, share it right away.
+            shareBugreport(info.id, info, /* showWarning */ false,
+                /* cancelNotificationWhenStoppingProgress */ false);
+            sendBugreportNotification(info, mTakingScreenshot);
+        } else {
+            // Asynchronously zip the file first, then share it.
+            shareAndPostNotificationForZippedBugreport(info, mTakingScreenshot);
+        }
+    }
+
+    /**
+     * Responsible for triggering a notification that allows the user to start a "share" intent with
+     * the bugreport.
+     */
+    private void triggerLocalNotification(final BugreportInfo info) {
         boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
         if (!isPlainText) {
             // Already zipped, send it right away.
@@ -1083,9 +1133,11 @@
         }
     }
 
-    private static Intent buildWarningIntent(Context context, Intent sendIntent) {
+    private static Intent buildWarningIntent(Context context, @Nullable Intent sendIntent) {
         final Intent intent = new Intent(context, BugreportWarningActivity.class);
-        intent.putExtra(Intent.EXTRA_INTENT, sendIntent);
+        if (sendIntent != null) {
+            intent.putExtra(Intent.EXTRA_INTENT, sendIntent);
+        }
         return intent;
     }
 
@@ -1163,11 +1215,30 @@
         return intent;
     }
 
+    private boolean hasUserDecidedNotToGetWarningMessage() {
+        return getWarningState(mContext, STATE_UNKNOWN) == STATE_HIDE;
+    }
+
+    private void maybeShowWarningMessageAndCloseNotification(int id) {
+        if (!hasUserDecidedNotToGetWarningMessage()) {
+            Intent warningIntent = buildWarningIntent(mContext, /* sendIntent */ null);
+            warningIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(warningIntent);
+        }
+        NotificationManager.from(mContext).cancel(id);
+    }
+
+    private void shareBugreport(int id, BugreportInfo sharedInfo) {
+        shareBugreport(id, sharedInfo, !hasUserDecidedNotToGetWarningMessage(),
+            /* cancelNotificationWhenStoppingProgress */ true);
+    }
+
     /**
      * Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
      * intent, but issuing a warning dialog the first time.
      */
-    private void shareBugreport(int id, BugreportInfo sharedInfo) {
+    private void shareBugreport(int id, BugreportInfo sharedInfo, boolean showWarning,
+            boolean cancelNotificationWhenStoppingProgress) {
         MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE);
         BugreportInfo info;
         synchronized (mLock) {
@@ -1199,7 +1270,7 @@
         boolean useChooser = true;
 
         // Send through warning dialog by default
-        if (getWarningState(mContext, STATE_UNKNOWN) != STATE_HIDE) {
+        if (showWarning) {
             notifIntent = buildWarningIntent(mContext, sendIntent);
             // No need to show a chooser in this case.
             useChooser = false;
@@ -1216,7 +1287,7 @@
         }
         synchronized (mLock) {
             // ... and stop watching this process.
-            stopProgressLocked(id);
+            stopProgressLocked(id, cancelNotificationWhenStoppingProgress);
         }
     }
 
@@ -1240,12 +1311,6 @@
         // Since adding the details can take a while, do it before notifying user.
         addDetailsToZipFile(info);
 
-        final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
-        shareIntent.setClass(mContext, BugreportProgressService.class);
-        shareIntent.setAction(INTENT_BUGREPORT_SHARE);
-        shareIntent.putExtra(EXTRA_ID, info.id);
-        shareIntent.putExtra(EXTRA_INFO, info);
-
         String content;
         content = takingScreenshot ?
                 mContext.getString(R.string.bugreport_finished_pending_screenshot_text)
@@ -1263,11 +1328,32 @@
         final Notification.Builder builder = newBaseNotification(mContext)
                 .setContentTitle(title)
                 .setTicker(title)
-                .setContentText(content)
-                .setContentIntent(PendingIntent.getService(mContext, info.id, shareIntent,
-                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
                 .setOnlyAlertOnce(false)
-                .setDeleteIntent(newCancelIntent(mContext, info));
+                .setContentText(content);
+
+        if (!mIsWatch) {
+            final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
+            shareIntent.setClass(mContext, BugreportProgressService.class);
+            shareIntent.setAction(INTENT_BUGREPORT_SHARE);
+            shareIntent.putExtra(EXTRA_ID, info.id);
+            shareIntent.putExtra(EXTRA_INFO, info);
+
+            builder.setContentIntent(PendingIntent.getService(mContext, info.id, shareIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
+                    .setDeleteIntent(newCancelIntent(mContext, info));
+        } else {
+            // Device is a watch.
+            if (hasUserDecidedNotToGetWarningMessage()) {
+                // No action button needed for the notification. User can swipe to dimiss.
+                builder.setActions(new Action[0]);
+            } else {
+                // Add action button to lead user to the warning screen.
+                builder.setActions(
+                        new Action.Builder(
+                                null, mContext.getString(R.string.bugreport_info_action),
+                        newBugreportDoneIntent(mContext, info)).build());
+            }
+        }
 
         if (!TextUtils.isEmpty(info.getName())) {
             builder.setSubText(info.getName());
@@ -1327,6 +1413,24 @@
     }
 
     /**
+     * Zips a bugreport, shares it, and sends for it a bugreport notification.
+     */
+    private void shareAndPostNotificationForZippedBugreport(final BugreportInfo info,
+            final boolean takingScreenshot) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                Looper.prepare();
+                zipBugreport(info);
+                shareBugreport(info.id, info, /* showWarning */ false,
+                /* cancelNotificationWhenStoppingProgress */ false);
+                sendBugreportNotification(info, mTakingScreenshot);
+                return null;
+            }
+        }.execute();
+    }
+
+    /**
      * Zips a bugreport file, returning the path to the new file (or to the
      * original in case of failure).
      */
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
index ecd1369..a44e236 100644
--- a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -54,9 +54,11 @@
 
         mSendIntent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
 
-        // We need to touch the extras to unpack them so they get migrated to
-        // ClipData correctly.
-        mSendIntent.hasExtra(Intent.EXTRA_STREAM);
+        if (mSendIntent != null) {
+            // We need to touch the extras to unpack them so they get migrated to
+            // ClipData correctly.
+            mSendIntent.hasExtra(Intent.EXTRA_STREAM);
+        }
 
         final AlertController.AlertParams ap = mAlertParams;
         ap.mView = LayoutInflater.from(this).inflate(R.layout.confirm_repeat, null);
@@ -84,7 +86,9 @@
         if (which == AlertDialog.BUTTON_POSITIVE) {
             // Remember confirm state, and launch target
             setWarningState(this, mConfirmRepeat.isChecked() ? STATE_HIDE : STATE_SHOW);
-            sendShareIntent(this, mSendIntent);
+            if (mSendIntent != null) {
+                sendShareIntent(this, mSendIntent);
+            }
         }
 
         finish();
diff --git a/packages/SystemUI/res/drawable/ic_list.xml b/packages/SystemUI/res/drawable/ic_list.xml
new file mode 100644
index 0000000..7ef5299
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_list.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 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.
+-->
+
+<!-- Remove when Fgs manager tile is removed -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M2,4h4v4h-4z"
+        android:fillColor="#000000"/>
+    <path
+        android:pathData="M8,4h14v4h-14z"
+        android:fillColor="#000000"/>
+    <path
+        android:pathData="M2,10h4v4h-4z"
+        android:fillColor="#000000"/>
+    <path
+        android:pathData="M8,10h14v4h-14z"
+        android:fillColor="#000000"/>
+    <path
+        android:pathData="M2,16h4v4h-4z"
+        android:fillColor="#000000"/>
+    <path
+        android:pathData="M8,16h14v4h-14z"
+        android:fillColor="#000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_seekbar_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_seekbar_background.xml
new file mode 100644
index 0000000..3a228d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_dialog_seekbar_background.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/background">
+        <shape>
+            <corners android:radius="28dp" />
+            <solid android:color="@android:color/transparent" />
+            <size
+                android:height="64dp"/>
+        </shape>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape>
+                <corners
+                    android:radius="28dp"/>
+                <size
+                    android:height="64dp"/>
+                <solid android:color="@*android:color/system_accent1_200" />
+            </shape>
+        </clip>
+    </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_solid_button_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_solid_button_background.xml
new file mode 100644
index 0000000..86f8b42
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_dialog_solid_button_background.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+       android:shape="rectangle">
+    <stroke
+        android:color="@android:color/transparent"
+        android:width="1dp"/>
+    <corners android:radius="20dp"/>
+    <padding
+        android:left="@dimen/media_output_dialog_button_padding_horizontal"
+        android:right="@dimen/media_output_dialog_button_padding_horizontal"
+        android:top="@dimen/media_output_dialog_button_padding_vertical"
+        android:bottom="@dimen/media_output_dialog_button_padding_vertical" />
+    <solid android:color="?androidprv:attr/colorAccentPrimaryVariant" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/media_output_item_background.xml b/packages/SystemUI/res/drawable/media_output_item_background.xml
new file mode 100644
index 0000000..8c23659
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_item_background.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+       android:shape="rectangle">
+    <corners
+        android:radius="16dp"/>
+    <solid android:color="?androidprv:attr/colorAccentSecondary" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/media_output_item_background_active.xml b/packages/SystemUI/res/drawable/media_output_item_background_active.xml
new file mode 100644
index 0000000..09dee95
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_item_background_active.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+       android:shape="rectangle">
+    <corners
+        android:radius="50dp"/>
+    <solid android:color="?androidprv:attr/colorAccentSecondary" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/media_output_status_check.xml b/packages/SystemUI/res/drawable/media_output_status_check.xml
new file mode 100644
index 0000000..4e17e48
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_status_check.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="?androidprv:attr/colorAccentPrimaryVariant"
+        android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_failed.xml b/packages/SystemUI/res/drawable/media_output_status_failed.xml
new file mode 100644
index 0000000..81fb92c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_status_failed.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="?androidprv:attr/colorAccentPrimaryVariant"
+        android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/fgs_manager_app_item.xml b/packages/SystemUI/res/layout/fgs_manager_app_item.xml
new file mode 100644
index 0000000..d034f4e
--- /dev/null
+++ b/packages/SystemUI/res/layout/fgs_manager_app_item.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginBottom="32dp"
+    android:orientation="horizontal"
+    android:gravity="center">
+
+  <ImageView
+      android:id="@+id/fgs_manager_app_item_icon"
+      android:layout_width="28dp"
+      android:layout_height="28dp"
+      android:layout_marginRight="12dp" />
+
+  <LinearLayout
+      android:layout_width="0dp"
+      android:layout_weight="1"
+      android:layout_height="wrap_content"
+      android:orientation="vertical">
+    <TextView
+        android:id="@+id/fgs_manager_app_item_label"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="start"
+        style="@style/TextAppearance.Dialog.Body" />
+    <TextView
+        android:id="@+id/fgs_manager_app_item_duration"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="start"
+        style="@style/FgsManagerAppDuration" />
+  </LinearLayout>
+
+  <Button
+      android:id="@+id/fgs_manager_app_item_stop_button"
+      android:layout_width="wrap_content"
+      android:layout_height="48dp"
+      android:text="@string/fgs_manager_app_item_stop_button_label"
+      android:layout_marginLeft="12dp"
+      style="?android:attr/buttonBarNeutralButtonStyle" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index cfba83b..8f8993f 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -17,7 +17,6 @@
 
 <com.android.systemui.statusbar.phone.KeyguardBottomAreaView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/keyguard_bottom_area"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
@@ -128,7 +127,8 @@
         android:layout_height="match_parent">
 
         <include layout="@layout/keyguard_bottom_area_overlay" />
-
     </FrameLayout>
 
+    <include layout="@layout/ambient_indication"
+             android:id="@+id/ambient_indication_container" />
 </com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index a64ef3e..4e2b4a6 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,24 +24,30 @@
 
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="96dp"
+        android:layout_height="wrap_content"
         android:gravity="start|center_vertical"
         android:paddingStart="16dp"
+        android:paddingTop="16dp"
+        android:paddingEnd="16dp"
+        android:paddingBottom="24dp"
         android:orientation="horizontal">
         <ImageView
             android:id="@+id/header_icon"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
+            android:layout_width="72dp"
+            android:layout_height="72dp"
             android:importantForAccessibility="no"/>
 
         <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingStart="16dp"
-            android:paddingTop="20dp"
-            android:paddingBottom="24dp"
-            android:paddingEnd="24dp"
+            android:layout_height="wrap_content"
+            android:paddingStart="12dp"
             android:orientation="vertical">
+            <ImageView
+                android:id="@+id/app_source_icon"
+                android:layout_width="20dp"
+                android:layout_height="20dp"
+                android:gravity="center_vertical"
+                android:importantForAccessibility="no"/>
             <TextView
                 android:id="@+id/header_title"
                 android:layout_width="wrap_content"
@@ -51,7 +57,7 @@
                 android:maxLines="1"
                 android:textColor="?android:attr/textColorPrimary"
                 android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-                android:textSize="20sp"/>
+                android:textSize="16sp"/>
             <TextView
                 android:id="@+id/header_subtitle"
                 android:layout_width="wrap_content"
@@ -59,17 +65,12 @@
                 android:gravity="center_vertical"
                 android:ellipsize="end"
                 android:maxLines="1"
-                android:textColor="?android:attr/textColorTertiary"
+                android:textColor="?android:attr/textColorSecondary"
                 android:fontFamily="roboto-regular"
-                android:textSize="16sp"/>
+                android:textSize="14sp"/>
         </LinearLayout>
     </LinearLayout>
 
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="?android:attr/listDivider"/>
-
     <LinearLayout
         android:id="@+id/device_list"
         android:layout_width="match_parent"
@@ -88,10 +89,10 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:layout_marginStart="24dp"
-        android:layout_marginBottom="18dp"
-        android:layout_marginEnd="24dp"
+        android:layout_marginTop="4dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginBottom="24dp"
+        android:layout_marginEnd="16dp"
         android:orientation="horizontal">
 
         <Button
@@ -110,7 +111,7 @@
 
         <Button
             android:id="@+id/done"
-            style="@style/MediaOutputRoundedOutlinedButton"
+            style="@style/MediaOutputRoundedButton"
             android:layout_width="wrap_content"
             android:layout_height="36dp"
             android:minWidth="0dp"
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index a5a7efa..2f5f8d6 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -17,26 +17,43 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/device_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical">
     <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="88dp"
-        android:paddingTop="24dp"
-        android:paddingBottom="16dp"
-        android:paddingStart="24dp"
-        android:paddingEnd="8dp">
+        android:layout_height="64dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="12dp">
+        <FrameLayout
+            android:id="@+id/item_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/media_output_item_background"
+            android:layout_gravity="center_vertical|start">
+            <SeekBar
+                android:id="@+id/volume_seekbar"
+                android:splitTrack="false"
+                android:visibility="gone"
+                android:paddingStart="0dp"
+                android:paddingEnd="0dp"
+                android:progressDrawable="@drawable/media_output_dialog_seekbar_background"
+                android:thumb="@null"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"/>
+        </FrameLayout>
 
         <FrameLayout
-            android:layout_width="48dp"
-            android:layout_height="48dp"
+            android:layout_width="56dp"
+            android:layout_height="64dp"
             android:layout_gravity="center_vertical|start">
             <ImageView
                 android:id="@+id/title_icon"
-                android:layout_width="48dp"
-                android:layout_height="48dp"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
                 android:layout_gravity="center"/>
         </FrameLayout>
 
@@ -45,55 +62,46 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical|start"
-            android:layout_marginStart="64dp"
+            android:layout_marginStart="56dp"
             android:ellipsize="end"
             android:maxLines="1"
-            android:textColor="?android:attr/textColorPrimary"
+            android:textColor="?androidprv:attr/colorAccentPrimaryVariant"
             android:textSize="16sp"/>
 
         <RelativeLayout
             android:id="@+id/two_line_layout"
             android:layout_width="wrap_content"
+            android:layout_gravity="center_vertical|start"
             android:layout_height="48dp"
-            android:layout_marginStart="48dp">
+            android:layout_marginStart="56dp">
             <TextView
                 android:id="@+id/two_line_title"
+                android:gravity="center_vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginStart="16dp"
-                android:layout_marginEnd="48dp"
                 android:ellipsize="end"
                 android:maxLines="1"
-                android:textColor="?android:attr/textColorPrimary"
+                android:textColor="?androidprv:attr/colorAccentPrimaryVariant"
                 android:textSize="16sp"/>
             <TextView
                 android:id="@+id/subtitle"
+                android:layout_gravity="center_vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginStart="16dp"
-                android:layout_marginEnd="15dp"
                 android:layout_marginTop="4dp"
                 android:layout_alignParentBottom="true"
                 android:ellipsize="end"
                 android:maxLines="1"
-                android:textColor="?android:attr/textColorSecondary"
+                android:textColor="?androidprv:attr/colorAccentPrimaryVariant"
                 android:textSize="14sp"
                 android:fontFamily="roboto-regular"
                 android:visibility="gone"/>
-            <SeekBar
-                android:id="@+id/volume_seekbar"
-                android:layout_marginTop="16dp"
-                android:layout_marginEnd="8dp"
-                style="@*android:style/Widget.DeviceDefault.SeekBar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_alignParentBottom="true"/>
             <ImageView
                 android:id="@+id/add_icon"
                 android:layout_width="24dp"
                 android:layout_height="24dp"
                 android:layout_gravity="right"
-                android:layout_marginEnd="24dp"
+                android:layout_marginEnd="16dp"
                 android:layout_alignParentRight="true"
                 android:src="@drawable/ic_add"
                 android:tint="?android:attr/colorAccent"
@@ -103,30 +111,33 @@
                 android:layout_width="24dp"
                 android:layout_height="24dp"
                 android:layout_gravity="right"
-                android:layout_marginEnd="24dp"
+                android:layout_marginEnd="16dp"
                 android:layout_alignParentRight="true"
                 android:button="@drawable/ic_check_box"
                 android:visibility="gone"
-                />
+            />
         </RelativeLayout>
 
         <ProgressBar
             android:id="@+id/volume_indeterminate_progress"
-            style="@*android:style/Widget.Material.ProgressBar.Horizontal"
-            android:layout_width="258dp"
-            android:layout_height="18dp"
-            android:layout_marginStart="64dp"
-            android:layout_marginTop="28dp"
+            style="?android:attr/progressBarStyleSmallTitle"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginEnd="16dp"
             android:indeterminate="true"
+            android:layout_gravity="right|center"
             android:indeterminateOnly="true"
             android:visibility="gone"/>
-    </FrameLayout>
 
-    <View
-        android:id="@+id/bottom_divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:layout_gravity="bottom"
-        android:background="?android:attr/listDivider"
-        android:visibility="gone"/>
+        <ImageView
+            android:id="@+id/media_output_item_status"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginEnd="16dp"
+            android:indeterminate="true"
+            android:layout_gravity="right|center"
+            android:indeterminateOnly="true"
+            android:importantForAccessibility="no"
+            android:visibility="gone"/>
+    </FrameLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index b4c9a93..2290964 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -128,9 +128,6 @@
             systemui:layout_constraintEnd_toEndOf="parent"
         />
 
-        <include layout="@layout/ambient_indication"
-            android:id="@+id/ambient_indication_container" />
-
         <include layout="@layout/photo_preview_overlay" />
 
         <include
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index c5b47d0..2b16ec2 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -16,7 +16,8 @@
  * limitations under the License.
  */
 -->
-<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <drawable name="notification_number_text_color">#ffffffff</drawable>
     <drawable name="system_bar_background">@color/system_bar_background_opaque</drawable>
     <color name="system_bar_background_opaque">#ff000000</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1bf2cd8..8b59d86 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -82,7 +82,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded
+        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,fgsmanager
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2ab4c0a..a437ae6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1085,11 +1085,13 @@
     <!-- Output switcher panel related dimensions -->
     <dimen name="media_output_dialog_list_margin">12dp</dimen>
     <dimen name="media_output_dialog_list_max_height">364dp</dimen>
-    <dimen name="media_output_dialog_header_album_icon_size">48dp</dimen>
+    <dimen name="media_output_dialog_header_album_icon_size">72dp</dimen>
     <dimen name="media_output_dialog_header_back_icon_size">32dp</dimen>
     <dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
-    <dimen name="media_output_dialog_icon_corner_radius">8dp</dimen>
+    <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
     <dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
+    <dimen name="media_output_dialog_button_padding_horizontal">16dp</dimen>
+    <dimen name="media_output_dialog_button_padding_vertical">8dp</dimen>
 
     <!-- Distance that the full shade transition takes in order for qs to fully transition to the
          shade -->
@@ -1293,4 +1295,6 @@
     <!-- ************************************************************************* -->
 
     <dimen name="keyguard_unfold_translation_x">16dp</dimen>
+
+    <dimen name="fgs_manager_min_width_minor">100%</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 21b4a42..300cb2d3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2203,7 +2203,7 @@
     <!-- Summary for disconnected status [CHAR LIMIT=50] -->
     <string name="media_output_dialog_disconnected">(disconnected)</string>
     <!-- Summary for connecting error message [CHAR LIMIT=NONE] -->
-    <string name="media_output_dialog_connect_failed">Couldn\'t connect. Try again.</string>
+    <string name="media_output_dialog_connect_failed">Can\'t switch. Tap to try again.</string>
     <!-- Title for pairing item [CHAR LIMIT=60] -->
     <string name="media_output_dialog_pairing_new">Pair new device</string>
 
@@ -2358,4 +2358,9 @@
 
     <!-- Title for User Switch dialog. [CHAR LIMIT=20] -->
     <string name="qs_user_switch_dialog_title">Select user</string>
+
+    <!-- Title for dialog listing applications currently running in the backing [CHAR LIMIT=NONE]-->
+    <string name="fgs_manager_dialog_title">Apps running in the background</string>
+    <!-- Label of the button to stop the app from running in the background [CHAR LIMIT=12]-->
+    <string name="fgs_manager_app_item_stop_button_label">Stop</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 94f1548..12a022d 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -454,6 +454,12 @@
         <item name="android:background">@drawable/media_output_dialog_button_background</item>
     </style>
 
+    <style name="MediaOutputRoundedButton" parent="@android:style/Widget.Material.Button">
+        <item name="android:background">@drawable/media_output_dialog_solid_button_background</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
     <style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
         <item name="android:windowActionBar">false</item>
         <item name="preferenceTheme">@style/TunerPreferenceTheme</item>
@@ -847,7 +853,6 @@
     <style name="Widget.SliceView.Panel">
         <item name="titleSize">16sp</item>
         <item name="rowStyle">@style/SliceRow</item>
-        <item name="android:background">?android:attr/colorBackgroundFloating</item>
     </style>
 
     <style name="SliceRow">
@@ -984,4 +989,14 @@
 
     <style name="InternetDialog.Divider.Active"/>
 
+    <style name="FgsManagerDialogTitle">
+        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textDirection">locale</item>
+    </style>
+
+    <style name="FgsManagerAppDuration">
+        <item name="android:fontFamily">?android:attr/textAppearanceSmall</item>
+        <item name="android:textDirection">locale</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index ed29bc7..5fdb497 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -298,4 +298,14 @@
         <item>Off</item>
         <item>On</item>
     </string-array>
+
+    <!-- State names for fgsmanager tile: unavailable, off, on.
+         This subtitle is shown when the tile is in that particular state but does not set its own
+         subtitle, so some of these may never appear on screen. They should still be translated as
+         if they could appear.[CHAR LIMIT=32] -->
+    <string-array name="tile_states_fgsmanager">
+        <item>Unavailable</item>
+        <item>Off</item>
+        <item>On</item>
+    </string-array>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
index c941d66..e4e0da6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
@@ -71,7 +71,9 @@
     public void addListener(@NonNull T listener) {
         Objects.requireNonNull(listener, "listener must be non-null");
 
-        mListeners.add(listener);
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
 
         if (mListeners.size() == 1) {
             mContentResolver.registerContentObserver(
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 794b9dd5..a10efa9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -158,12 +158,13 @@
 
     @MainThread
     void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+            float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
             @Nullable IRemoteMagnificationAnimationCallback callback) {
         final WindowMagnificationController windowMagnificationController =
                 mMagnificationControllerSupplier.get(displayId);
         if (windowMagnificationController != null) {
-            windowMagnificationController.enableWindowMagnification(scale, centerX,
-                    centerY, callback);
+            windowMagnificationController.enableWindowMagnification(scale, centerX, centerY,
+                    magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY, callback);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
index 1bfa9c1..dc1e005 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -62,6 +62,8 @@
     private final ValueAnimator mValueAnimator;
     private final AnimationSpec mStartSpec = new AnimationSpec();
     private final AnimationSpec mEndSpec = new AnimationSpec();
+    private float mMagnificationFrameOffsetRatioX = 0f;
+    private float mMagnificationFrameOffsetRatioY = 0f;
     private final Context mContext;
     // Called when the animation is ended successfully without cancelling or mStartSpec and
     // mEndSpec are equal.
@@ -88,7 +90,8 @@
     }
 
     /**
-     * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
+     * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float,
+     * float, float, IRemoteMagnificationAnimationCallback)}
      * with transition animation. If the window magnification is not enabled, the scale will start
      * from 1.0 and the center won't be changed during the animation. If {@link #mState} is
      * {@code STATE_DISABLING}, the animation runs in reverse.
@@ -106,16 +109,48 @@
      */
     void enableWindowMagnification(float scale, float centerX, float centerY,
             @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
+        enableWindowMagnification(scale, centerX, centerY, 0f, 0f, animationCallback);
+    }
+
+    /**
+     * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float,
+     * float, float, IRemoteMagnificationAnimationCallback)}
+     * with transition animation. If the window magnification is not enabled, the scale will start
+     * from 1.0 and the center won't be changed during the animation. If {@link #mState} is
+     * {@code STATE_DISABLING}, the animation runs in reverse.
+     *
+     * @param scale   The target scale, or {@link Float#NaN} to leave unchanged.
+     * @param centerX The screen-relative X coordinate around which to center for magnification,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param centerY The screen-relative Y coordinate around which to center for magnification,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param magnificationFrameOffsetRatioX Indicate the X coordinate offset between
+     *                                       frame position X and centerX
+     * @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset between
+     *                                       frame position Y and centerY
+     * @param animationCallback Called when the transition is complete, the given arguments
+     *                          are as same as current values, or the transition is interrupted
+     *                          due to the new transition request.
+     *
+     * @see #onAnimationUpdate(ValueAnimator)
+     */
+    void enableWindowMagnification(float scale, float centerX, float centerY,
+            float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
+            @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
         if (mController == null) {
             return;
         }
         sendAnimationCallback(false);
+        mMagnificationFrameOffsetRatioX = magnificationFrameOffsetRatioX;
+        mMagnificationFrameOffsetRatioY = magnificationFrameOffsetRatioY;
+
         // Enable window magnification without animation immediately.
         if (animationCallback == null) {
             if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
                 mValueAnimator.cancel();
             }
-            mController.enableWindowMagnification(scale, centerX, centerY);
+            mController.enableWindowMagnificationInternal(scale, centerX, centerY,
+                    mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
             setState(STATE_ENABLED);
             return;
         }
@@ -123,7 +158,8 @@
         setupEnableAnimationSpecs(scale, centerX, centerY);
         if (mEndSpec.equals(mStartSpec)) {
             if (mState == STATE_DISABLED) {
-                mController.enableWindowMagnification(scale, centerX, centerY);
+                mController.enableWindowMagnificationInternal(scale, centerX, centerY,
+                        mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
             } else if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
                 mValueAnimator.cancel();
             }
@@ -273,7 +309,8 @@
                 mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract;
         final float centerY =
                 mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract;
-        mController.enableWindowMagnification(sentScale, centerX, centerY);
+        mController.enableWindowMagnificationInternal(sentScale, centerX, centerY,
+                mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
     }
 
     private static ValueAnimator newValueAnimator(Resources resources) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
index 92cd8b1..2133da2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
@@ -49,11 +49,13 @@
     }
 
     @Override
-    public void enableWindowMagnification(int displayId, float scale, float centerX,
-            float centerY, IRemoteMagnificationAnimationCallback callback) {
+    public void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+            float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
+            IRemoteMagnificationAnimationCallback callback) {
         mHandler.post(
                 () -> mWindowMagnification.enableWindowMagnification(displayId, scale, centerX,
-                        centerY, callback));
+                        centerY, magnificationFrameOffsetRatioX,
+                        magnificationFrameOffsetRatioY, callback));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 2507004..b064ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -95,17 +95,46 @@
     @Surface.Rotation
     @VisibleForTesting
     int mRotation;
-    private final Rect mMagnificationFrame = new Rect();
     private final SurfaceControl.Transaction mTransaction;
 
     private final WindowManager mWm;
 
     private float mScale;
 
+    /**
+     * MagnificationFrame represents the bound of {@link #mMirrorSurface} and is constrained
+     * by the {@link #mMagnificationFrameBoundary}.
+     * We use MagnificationFrame to calculate the position of {@link #mMirrorView}.
+     * We combine MagnificationFrame with {@link #mMagnificationFrameOffsetX} and
+     * {@link #mMagnificationFrameOffsetY} to calculate the position of {@link #mSourceBounds}.
+     */
+    private final Rect mMagnificationFrame = new Rect();
     private final Rect mTmpRect = new Rect();
+
+    /**
+     * MirrorViewBounds is the bound of the {@link #mMirrorView} which displays the magnified
+     * content.
+     * {@link #mMirrorView}'s center is equal to {@link #mMagnificationFrame}'s center.
+     */
     private final Rect mMirrorViewBounds = new Rect();
+
+    /**
+     * SourceBound is the bound of the magnified region which projects the magnified content.
+     * SourceBound's center is equal to the parameters centerX and centerY in
+     * {@link WindowMagnificationController#enableWindowMagnificationInternal(float, float, float)}}
+     * but it is calculated from {@link #mMagnificationFrame}'s center in the runtime.
+     */
     private final Rect mSourceBounds = new Rect();
 
+    /**
+     * The relation of centers between {@link #mSourceBounds} and {@link #mMagnificationFrame} is
+     * calculated in {@link #calculateSourceBounds(Rect, float)} and the equations are as following:
+     *      MagnificationFrame = SourceBound (e.g., centerX & centerY) + MagnificationFrameOffset
+     *      SourceBound = MagnificationFrame - MagnificationFrameOffset
+     */
+    private int mMagnificationFrameOffsetX = 0;
+    private int mMagnificationFrameOffsetY = 0;
+
     // The root of the mirrored content
     private SurfaceControl mMirrorSurface;
 
@@ -123,6 +152,7 @@
     private final Runnable mMirrorViewRunnable;
     private final Runnable mUpdateStateDescriptionRunnable;
     private final Runnable mWindowInsetChangeRunnable;
+    // MirrorView is the mirror window which displays the magnified content.
     private View mMirrorView;
     private SurfaceView mMirrorSurfaceView;
     private int mMirrorSurfaceMargin;
@@ -339,7 +369,7 @@
         // window size changed not caused by rotation.
         if (isWindowVisible() && reCreateWindow) {
             deleteWindowMagnification();
-            enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
+            enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN);
         }
     }
 
@@ -633,6 +663,26 @@
         int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale));
         int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale));
         mSourceBounds.set(left, top, right, bottom);
+
+        // SourceBound's center is equal to center[X,Y] but calculated from MagnificationFrame's
+        // center. The relation between SourceBound and MagnificationFrame is as following:
+        //          MagnificationFrame = SourceBound (center[X,Y]) + MagnificationFrameOffset
+        //          SourceBound = MagnificationFrame - MagnificationFrameOffset
+        mSourceBounds.offset(-mMagnificationFrameOffsetX, -mMagnificationFrameOffsetY);
+
+        if (mSourceBounds.left < 0) {
+            mSourceBounds.offsetTo(0, mSourceBounds.top);
+        } else if (mSourceBounds.right > mWindowBounds.width()) {
+            mSourceBounds.offsetTo(mWindowBounds.width() - mSourceBounds.width(),
+                    mSourceBounds.top);
+        }
+
+        if (mSourceBounds.top < 0) {
+            mSourceBounds.offsetTo(mSourceBounds.left, 0);
+        } else if (mSourceBounds.bottom > mWindowBounds.height()) {
+            mSourceBounds.offsetTo(mSourceBounds.left,
+                    mWindowBounds.height() - mSourceBounds.height());
+        }
     }
 
     private void calculateMagnificationFrameBoundary() {
@@ -646,11 +696,31 @@
         final int scaledWidth = (int) (halfWidth / mScale);
         // The scaled half height of magnified region.
         final int scaledHeight = (int) (halfHeight / mScale);
-        final int exceededWidth = halfWidth - scaledWidth;
-        final int exceededHeight = halfHeight - scaledHeight;
 
-        mMagnificationFrameBoundary.set(-exceededWidth, -exceededHeight,
-                mWindowBounds.width() + exceededWidth, mWindowBounds.height() + exceededHeight);
+        // MagnificationFrameBoundary constrain the space of MagnificationFrame, and it also has
+        // to leave enough space for SourceBound to magnify the whole screen space.
+        // However, there is an offset between SourceBound and MagnificationFrame.
+        // The relation between SourceBound and MagnificationFrame is as following:
+        //      SourceBound = MagnificationFrame - MagnificationFrameOffset
+        // Therefore, we have to adjust the exceededBoundary based on the offset.
+        //
+        // We have to increase the offset space for the SourceBound edges which are located in
+        // the MagnificationFrame. For example, if the offsetX and offsetY are negative, which
+        // means SourceBound is at right-bottom size of MagnificationFrame, the left and top
+        // edges of SourceBound are located in MagnificationFrame. So, we have to leave extra
+        // offset space at left and top sides and don't have to leave extra space at right and
+        // bottom sides.
+        final int exceededLeft = Math.max(halfWidth - scaledWidth - mMagnificationFrameOffsetX, 0);
+        final int exceededRight = Math.max(halfWidth - scaledWidth + mMagnificationFrameOffsetX, 0);
+        final int exceededTop = Math.max(halfHeight - scaledHeight - mMagnificationFrameOffsetY, 0);
+        final int exceededBottom = Math.max(halfHeight - scaledHeight + mMagnificationFrameOffsetY,
+                0);
+
+        mMagnificationFrameBoundary.set(
+                -exceededLeft,
+                -exceededTop,
+                mWindowBounds.width() + exceededRight,
+                mWindowBounds.height() + exceededBottom);
     }
 
     /**
@@ -711,24 +781,30 @@
     }
 
     /**
-     * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
+     * Wraps {@link WindowMagnificationController#enableWindowMagnificationInternal(float, float,
+     * float, float, float)}
      * with transition animation. If the window magnification is not enabled, the scale will start
      * from 1.0 and the center won't be changed during the animation. If animator is
      * {@code STATE_DISABLING}, the animation runs in reverse.
      *
      * @param scale   The target scale, or {@link Float#NaN} to leave unchanged.
-     * @param centerX The screen-relative X coordinate around which to center,
+     * @param centerX The screen-relative X coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
-     * @param centerY The screen-relative Y coordinate around which to center,
+     * @param centerY The screen-relative Y coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
+     * @param magnificationFrameOffsetRatioX Indicate the X coordinate offset
+     *                                       between frame position X and centerX
+     * @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset
+     *                                       between frame position Y and centerY
      * @param animationCallback Called when the transition is complete, the given arguments
      *                          are as same as current values, or the transition is interrupted
      *                          due to the new transition request.
      */
     void enableWindowMagnification(float scale, float centerX, float centerY,
+            float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
             @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
-        mAnimationController.enableWindowMagnification(scale, centerX,
-                centerY, animationCallback);
+        mAnimationController.enableWindowMagnification(scale, centerX, centerY,
+                magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY, animationCallback);
     }
 
     /**
@@ -738,21 +814,56 @@
      * be consistent with the behavior of display magnification.
      *
      * @param scale   the target scale, or {@link Float#NaN} to leave unchanged
-     * @param centerX the screen-relative X coordinate around which to center,
+     * @param centerX the screen-relative X coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
-     * @param centerY the screen-relative Y coordinate around which to center,
+     * @param centerY the screen-relative Y coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
      */
-    void enableWindowMagnification(float scale, float centerX, float centerY) {
+    void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
+        enableWindowMagnificationInternal(scale, centerX, centerY, Float.NaN, Float.NaN);
+    }
+
+    /**
+     * Enables window magnification with specified parameters. If the given scale is <strong>less
+     * than or equal to 1.0f<strong>, then
+     * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
+     * be consistent with the behavior of display magnification.
+     *
+     * @param scale   the target scale, or {@link Float#NaN} to leave unchanged
+     * @param centerX the screen-relative X coordinate around which to center for magnification,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param centerY the screen-relative Y coordinate around which to center for magnification,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param magnificationFrameOffsetRatioX Indicate the X coordinate offset
+     *                                       between frame position X and centerX,
+     *                                       or {@link Float#NaN} to leave unchanged.
+     * @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset
+     *                                       between frame position Y and centerY,
+     *                                       or {@link Float#NaN} to leave unchanged.
+     */
+    void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
+            float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY) {
         if (Float.compare(scale, 1.0f)  <= 0) {
             deleteWindowMagnification();
             return;
         }
 
+        mMagnificationFrameOffsetX = Float.isNaN(magnificationFrameOffsetRatioX)
+                ? mMagnificationFrameOffsetX
+                : (int) (mMagnificationFrame.width() / 2 * magnificationFrameOffsetRatioX);
+        mMagnificationFrameOffsetY = Float.isNaN(magnificationFrameOffsetRatioY)
+                ? mMagnificationFrameOffsetY
+                : (int) (mMagnificationFrame.height() / 2 * magnificationFrameOffsetRatioY);
+
+        // The relation of centers between SourceBound and MagnificationFrame is as following:
+        // MagnificationFrame = SourceBound (e.g., centerX & centerY) + MagnificationFrameOffset
+        final float newMagnificationFrameCenterX = centerX + mMagnificationFrameOffsetX;
+        final float newMagnificationFrameCenterY = centerY + mMagnificationFrameOffsetY;
+
         final float offsetX = Float.isNaN(centerX) ? 0
-                : centerX - mMagnificationFrame.exactCenterX();
+                : newMagnificationFrameCenterX - mMagnificationFrame.exactCenterX();
         final float offsetY = Float.isNaN(centerY) ? 0
-                : centerY - mMagnificationFrame.exactCenterY();
+                : newMagnificationFrameCenterY - mMagnificationFrame.exactCenterY();
         mScale = Float.isNaN(scale) ? mScale : scale;
 
         calculateMagnificationFrameBoundary();
@@ -774,7 +885,7 @@
         if (mAnimationController.isAnimating() || !isWindowVisible() || mScale == scale) {
             return;
         }
-        enableWindowMagnification(scale, Float.NaN, Float.NaN);
+        enableWindowMagnificationInternal(scale, Float.NaN, Float.NaN);
         mHandler.removeCallbacks(mUpdateStateDescriptionRunnable);
         mHandler.postDelayed(mUpdateStateDescriptionRunnable, UPDATE_STATE_DESCRIPTION_DELAY_MS);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index cff6cf1..cc5a792 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -98,7 +98,8 @@
         mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
 
-        init();
+        mIsKeyguardVisible = false;
+        mIsAccessibilityManagerServiceReady = false;
     }
 
     /**
@@ -124,9 +125,8 @@
         handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
     }
 
-    private void init() {
-        mIsKeyguardVisible = false;
-        mIsAccessibilityManagerServiceReady = false;
+    /** Initializes the AccessibilityFloatingMenuController configurations. */
+    public void init() {
         mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
         mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
         registerContentObservers();
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt
new file mode 100644
index 0000000..42f3512
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2021 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.fgsmanager
+
+import android.content.Context
+import android.os.Bundle
+import android.text.format.DateUtils
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.GuardedBy
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.fgsmanager.FgsManagerDialogController.RunningApp
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.time.SystemClock
+import java.util.concurrent.Executor
+
+/**
+ * Dialog which shows a list of running foreground services and offers controls to them
+ */
+class FgsManagerDialog(
+    context: Context,
+    private val executor: Executor,
+    @Background private val backgroundExecutor: Executor,
+    private val systemClock: SystemClock,
+    private val fgsManagerDialogController: FgsManagerDialogController
+) : SystemUIDialog(context, R.style.Theme_SystemUI_Dialog) {
+
+    private val appListRecyclerView: RecyclerView = RecyclerView(this.context)
+    private val adapter: AppListAdapter = AppListAdapter()
+
+    init {
+        setTitle(R.string.fgs_manager_dialog_title)
+        setView(appListRecyclerView)
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        appListRecyclerView.layoutManager = LinearLayoutManager(context)
+        fgsManagerDialogController.registerDialogForChanges(
+                object : FgsManagerDialogController.FgsManagerDialogCallback {
+                    override fun onRunningAppsChanged(apps: List<RunningApp>) {
+                        executor.execute {
+                            adapter.setData(apps)
+                        }
+                    }
+                }
+        )
+        appListRecyclerView.adapter = adapter
+        backgroundExecutor.execute { adapter.setData(fgsManagerDialogController.runningAppList) }
+    }
+
+    private inner class AppListAdapter : RecyclerView.Adapter<AppItemViewHolder>() {
+        private val lock = Any()
+
+        @GuardedBy("lock")
+        private val data: MutableList<RunningApp> = ArrayList()
+        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppItemViewHolder {
+            return AppItemViewHolder(LayoutInflater.from(context)
+                            .inflate(R.layout.fgs_manager_app_item, parent, false))
+        }
+
+        override fun onBindViewHolder(holder: AppItemViewHolder, position: Int) {
+            var runningApp: RunningApp
+            synchronized(lock) {
+                runningApp = data[position]
+            }
+            with(holder) {
+                iconView.setImageDrawable(runningApp.mIcon)
+                appLabelView.text = runningApp.mAppLabel
+                durationView.text = DateUtils.formatDuration(
+                        Math.max(systemClock.elapsedRealtime() - runningApp.mTimeStarted, 60000),
+                        DateUtils.LENGTH_MEDIUM)
+                stopButton.setOnClickListener {
+                    fgsManagerDialogController
+                            .stopAllFgs(runningApp.mUserId, runningApp.mPackageName)
+                }
+            }
+        }
+
+        override fun getItemCount(): Int {
+            synchronized(lock) { return data.size }
+        }
+
+        fun setData(newData: List<RunningApp>) {
+            var oldData: List<RunningApp>
+            synchronized(lock) {
+                oldData = ArrayList(data)
+                data.clear()
+                data.addAll(newData)
+            }
+
+            DiffUtil.calculateDiff(object : DiffUtil.Callback() {
+                override fun getOldListSize(): Int {
+                    return oldData.size
+                }
+
+                override fun getNewListSize(): Int {
+                    return newData.size
+                }
+
+                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int):
+                        Boolean {
+                    return oldData[oldItemPosition] == newData[newItemPosition]
+                }
+
+                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int):
+                        Boolean {
+                    return true // TODO, look into updating the time subtext
+                }
+            }).dispatchUpdatesTo(this)
+        }
+    }
+
+    private class AppItemViewHolder(parent: View) : RecyclerView.ViewHolder(parent) {
+        val appLabelView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_label)
+        val durationView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_duration)
+        val iconView: ImageView = parent.requireViewById(R.id.fgs_manager_app_item_icon)
+        val stopButton: Button = parent.requireViewById(R.id.fgs_manager_app_item_stop_button)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt
new file mode 100644
index 0000000..159ed39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 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.fgsmanager
+
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.NameNotFoundException
+import android.graphics.drawable.Drawable
+import android.os.Handler
+import android.os.UserHandle
+import android.util.ArrayMap
+import android.util.Log
+import androidx.annotation.GuardedBy
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.policy.RunningFgsController
+import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
+import javax.inject.Inject
+
+/**
+ * Controls events relevant to FgsManagerDialog
+ */
+class FgsManagerDialogController @Inject constructor(
+    private val packageManager: PackageManager,
+    @Background private val backgroundHandler: Handler,
+    private val runningFgsController: RunningFgsController
+) : RunningFgsController.Callback {
+    private val lock = Any()
+    private val clearCacheToken = Any()
+
+    @GuardedBy("lock")
+    private var runningApps: Map<UserPackageTime, RunningApp>? = null
+    @GuardedBy("lock")
+    private var listener: FgsManagerDialogCallback? = null
+
+    interface FgsManagerDialogCallback {
+        fun onRunningAppsChanged(apps: List<RunningApp>)
+    }
+
+    data class RunningApp(
+        val mUserId: Int,
+        val mPackageName: String,
+        val mAppLabel: CharSequence,
+        val mIcon: Drawable,
+        val mTimeStarted: Long
+    )
+
+    val runningAppList: List<RunningApp>
+        get() {
+            synchronized(lock) {
+                if (runningApps == null) {
+                    onFgsPackagesChangedLocked(runningFgsController.getPackagesWithFgs())
+                }
+                return convertToRunningAppList(runningApps!!)
+            }
+        }
+
+    fun registerDialogForChanges(callback: FgsManagerDialogCallback) {
+        synchronized(lock) {
+            runningFgsController.addCallback(this)
+            listener = callback
+            backgroundHandler.removeCallbacksAndMessages(clearCacheToken)
+        }
+    }
+
+    fun onFinishDialog() {
+        synchronized(lock) {
+            listener = null
+            // Keep data such as icons cached for some time since loading can be slow
+            backgroundHandler.postDelayed(
+                    {
+                        synchronized(lock) {
+                            runningFgsController.removeCallback(this)
+                            runningApps = null
+                        }
+                    }, clearCacheToken, RUNNING_APP_CACHE_TIMEOUT_MILLIS)
+        }
+    }
+
+    private fun onRunningAppsChanged(apps: ArrayMap<UserPackageTime, RunningApp>) {
+        listener?.let {
+            backgroundHandler.post { it.onRunningAppsChanged(convertToRunningAppList(apps)) }
+        }
+    }
+
+    override fun onFgsPackagesChanged(packages: List<UserPackageTime>) {
+        backgroundHandler.post {
+            synchronized(lock) { onFgsPackagesChangedLocked(packages) }
+        }
+    }
+
+    /**
+     * Run on background thread
+     */
+    private fun onFgsPackagesChangedLocked(packages: List<UserPackageTime>) {
+        val newRunningApps = ArrayMap<UserPackageTime, RunningApp>()
+        for (packageWithFgs in packages) {
+            val ra = runningApps?.get(packageWithFgs)
+            if (ra == null) {
+                val userId = packageWithFgs.userId
+                val packageName = packageWithFgs.packageName
+                try {
+                    val ai = packageManager.getApplicationInfo(packageName, 0)
+                    var icon = packageManager.getApplicationIcon(ai)
+                    icon = packageManager.getUserBadgedIcon(icon,
+                            UserHandle.of(userId))
+                    val label = packageManager.getApplicationLabel(ai)
+                    newRunningApps[packageWithFgs] = RunningApp(userId, packageName,
+                            label, icon, packageWithFgs.startTimeMillis)
+                } catch (e: NameNotFoundException) {
+                    Log.e(LOG_TAG,
+                            "Application info not found: $packageName", e)
+                }
+            } else {
+                newRunningApps[packageWithFgs] = ra
+            }
+        }
+        runningApps = newRunningApps
+        onRunningAppsChanged(newRunningApps)
+    }
+
+    fun stopAllFgs(userId: Int, packageName: String) {
+        runningFgsController.stopFgs(userId, packageName)
+    }
+
+    companion object {
+        private val LOG_TAG = FgsManagerDialogController::class.java.simpleName
+        private const val RUNNING_APP_CACHE_TIMEOUT_MILLIS: Long = 20_000
+
+        private fun convertToRunningAppList(apps: Map<UserPackageTime, RunningApp>):
+                List<RunningApp> {
+            val result = mutableListOf<RunningApp>()
+            result.addAll(apps.values)
+            result.sortWith { a: RunningApp, b: RunningApp ->
+                b.mTimeStarted.compareTo(a.mTimeStarted)
+            }
+            return result
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt
new file mode 100644
index 0000000..2874929
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 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.fgsmanager
+
+import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.animation.DialogLaunchAnimator
+import android.content.DialogInterface
+import android.view.View
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.time.SystemClock
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * Factory to create [FgsManagerDialog] instances
+ */
+@SysUISingleton
+class FgsManagerDialogFactory
+@Inject constructor(
+    private val context: Context,
+    @Main private val executor: Executor,
+    @Background private val backgroundExecutor: Executor,
+    private val systemClock: SystemClock,
+    private val dialogLaunchAnimator: DialogLaunchAnimator,
+    private val fgsManagerDialogController: FgsManagerDialogController
+) {
+
+    val lock = Any()
+
+    companion object {
+        private var fgsManagerDialog: FgsManagerDialog? = null
+    }
+
+    /**
+     * Creates the dialog if it doesn't exist
+     */
+    fun create(viewLaunchedFrom: View?) {
+        if (fgsManagerDialog == null) {
+            fgsManagerDialog = FgsManagerDialog(context, executor, backgroundExecutor,
+                    systemClock, fgsManagerDialogController)
+            fgsManagerDialog!!.setOnDismissListener { i: DialogInterface? ->
+                fgsManagerDialogController.onFinishDialog()
+                fgsManagerDialog = null
+            }
+            dialogLaunchAnimator.showFromView(fgsManagerDialog!!, viewLaunchedFrom!!)
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 113ba59..5fa66cd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -40,6 +40,8 @@
 
     private static final String TAG = "MediaOutputAdapter";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final float DEVICE_DISCONNECTED_ALPHA = 0.5f;
+    private static final float DEVICE_CONNECTED_ALPHA = 1f;
 
     private final MediaOutputDialog mMediaOutputDialog;
     private ViewGroup mConnectedItem;
@@ -109,8 +111,8 @@
             if (currentlyConnected) {
                 mConnectedItem = mContainerLayout;
             }
-            mBottomDivider.setVisibility(View.GONE);
             mCheckBox.setVisibility(View.GONE);
+            mStatusIcon.setVisibility(View.GONE);
             if (currentlyConnected && mController.isActiveRemoteDevice(device)
                     && mController.getSelectableMediaDevice().size() > 0) {
                 // Init active device layout
@@ -124,35 +126,42 @@
             if (mCurrentActivePosition == position) {
                 mCurrentActivePosition = -1;
             }
+            if (device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
+                    && !device.isConnected()) {
+                mTitleText.setAlpha(DEVICE_DISCONNECTED_ALPHA);
+                mTitleIcon.setAlpha(DEVICE_DISCONNECTED_ALPHA);
+            } else {
+                mTitleText.setAlpha(DEVICE_CONNECTED_ALPHA);
+                mTitleIcon.setAlpha(DEVICE_CONNECTED_ALPHA);
+            }
+
             if (mController.isTransferring()) {
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING
                         && !mController.hasAdjustVolumeUserRestriction()) {
-                    setTwoLineLayout(device, true /* bFocused */, false /* showSeekBar*/,
-                            true /* showProgressBar */, false /* showSubtitle */);
+                    setSingleLineLayout(getItemTitle(device), true /* bFocused */,
+                            false /* showSeekBar*/,
+                            true /* showProgressBar */, false /* showStatus */);
                 } else {
                     setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                 }
             } else {
                 // Set different layout for each device
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
+                    mStatusIcon.setImageDrawable(
+                            mContext.getDrawable(R.drawable.media_output_status_failed));
                     setTwoLineLayout(device, false /* bFocused */,
                             false /* showSeekBar */, false /* showProgressBar */,
-                            true /* showSubtitle */);
+                            true /* showSubtitle */, true /* showStatus */);
                     mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
                     mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
                 } else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
-                    setTwoLineLayout(device, true /* bFocused */, true /* showSeekBar */,
-                            false /* showProgressBar */, false /* showSubtitle */);
+                    mStatusIcon.setImageDrawable(
+                            mContext.getDrawable(R.drawable.media_output_status_check));
+                    setSingleLineLayout(getItemTitle(device), true /* bFocused */,
+                            true /* showSeekBar */,
+                            false /* showProgressBar */, true /* showStatus */);
                     initSeekbar(device);
                     mCurrentActivePosition = position;
-                } else if (
-                        device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
-                                && !device.isConnected()) {
-                    setTwoLineLayout(device, false /* bFocused */,
-                            false /* showSeekBar */, false /* showProgressBar */,
-                            true /* showSubtitle */);
-                    mSubTitleText.setText(R.string.media_output_dialog_disconnected);
-                    mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
                 } else {
                     setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                     mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
@@ -165,7 +174,6 @@
             if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
                 mCheckBox.setVisibility(View.GONE);
                 mAddIcon.setVisibility(View.GONE);
-                mBottomDivider.setVisibility(View.GONE);
                 setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
                         false /* bFocused */);
                 final Drawable d = mContext.getDrawable(R.drawable.ic_add);
@@ -175,7 +183,6 @@
                 mContainerLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));
             } else if (customizedItem == CUSTOMIZED_ITEM_DYNAMIC_GROUP) {
                 mConnectedItem = mContainerLayout;
-                mBottomDivider.setVisibility(View.GONE);
                 mCheckBox.setVisibility(View.GONE);
                 if (mController.getSelectableMediaDevice().size() > 0) {
                     mAddIcon.setVisibility(View.VISIBLE);
@@ -200,7 +207,6 @@
             }
 
             mCurrentActivePosition = -1;
-            playSwitchingAnim(mConnectedItem, view);
             mController.connectDevice(device);
             device.setState(MediaDeviceState.STATE_CONNECTING);
             if (!isAnimating()) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 54e40f1..dc4aaa9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -30,6 +30,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.CheckBox;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
@@ -40,7 +41,6 @@
 import androidx.annotation.NonNull;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.media.MediaDevice;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.R;
@@ -113,6 +113,7 @@
         private static final int ANIM_DURATION = 200;
 
         final LinearLayout mContainerLayout;
+        final FrameLayout mItemLayout;
         final TextView mTitleText;
         final TextView mTwoLineTitleText;
         final TextView mSubTitleText;
@@ -121,13 +122,14 @@
         final ProgressBar mProgressBar;
         final SeekBar mSeekBar;
         final RelativeLayout mTwoLineLayout;
-        final View mBottomDivider;
+        final ImageView mStatusIcon;
         final CheckBox mCheckBox;
         private String mDeviceId;
 
         MediaDeviceBaseViewHolder(View view) {
             super(view);
             mContainerLayout = view.requireViewById(R.id.device_container);
+            mItemLayout = view.requireViewById(R.id.item_layout);
             mTitleText = view.requireViewById(R.id.title);
             mSubTitleText = view.requireViewById(R.id.subtitle);
             mTwoLineLayout = view.requireViewById(R.id.two_line_layout);
@@ -135,8 +137,8 @@
             mTitleIcon = view.requireViewById(R.id.title_icon);
             mProgressBar = view.requireViewById(R.id.volume_indeterminate_progress);
             mSeekBar = view.requireViewById(R.id.volume_seekbar);
-            mBottomDivider = view.requireViewById(R.id.bottom_divider);
             mAddIcon = view.requireViewById(R.id.add_icon);
+            mStatusIcon = view.requireViewById(R.id.media_output_item_status);
             mCheckBox = view.requireViewById(R.id.check_box);
         }
 
@@ -156,11 +158,26 @@
         abstract void onBind(int customizedItem, boolean topMargin, boolean bottomMargin);
 
         void setSingleLineLayout(CharSequence title, boolean bFocused) {
+            setSingleLineLayout(title, bFocused, false, false, false);
+        }
+
+        void setSingleLineLayout(CharSequence title, boolean bFocused, boolean showSeekBar,
+                boolean showProgressBar, boolean showStatus) {
             mTwoLineLayout.setVisibility(View.GONE);
-            mProgressBar.setVisibility(View.GONE);
+            final Drawable backgroundDrawable =
+                    showSeekBar
+                            ? mContext.getDrawable(R.drawable.media_output_item_background_active)
+                                    .mutate() : mContext.getDrawable(
+                            R.drawable.media_output_item_background)
+                            .mutate();
+            mItemLayout.setBackground(backgroundDrawable);
+            mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
+            mSeekBar.setAlpha(1);
+            mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);
+            mStatusIcon.setVisibility(showStatus ? View.VISIBLE : View.GONE);
+            mTitleText.setText(title);
             mTitleText.setVisibility(View.VISIBLE);
             mTitleText.setTranslationY(0);
-            mTitleText.setText(title);
             if (bFocused) {
                 mTitleText.setTypeface(Typeface.create(mContext.getString(
                         com.android.internal.R.string.config_headlineFontFamilyMedium),
@@ -173,20 +190,32 @@
 
         void setTwoLineLayout(MediaDevice device, boolean bFocused, boolean showSeekBar,
                 boolean showProgressBar, boolean showSubtitle) {
-            setTwoLineLayout(device, null, bFocused, showSeekBar, showProgressBar, showSubtitle);
+            setTwoLineLayout(device, null, bFocused, showSeekBar, showProgressBar, showSubtitle,
+                    false);
+        }
+
+        void setTwoLineLayout(MediaDevice device, boolean bFocused, boolean showSeekBar,
+                boolean showProgressBar, boolean showSubtitle, boolean showStatus) {
+            setTwoLineLayout(device, null, bFocused, showSeekBar, showProgressBar, showSubtitle,
+                    showStatus);
         }
 
         void setTwoLineLayout(CharSequence title, boolean bFocused, boolean showSeekBar,
                 boolean showProgressBar, boolean showSubtitle) {
-            setTwoLineLayout(null, title, bFocused, showSeekBar, showProgressBar, showSubtitle);
+            setTwoLineLayout(null, title, bFocused, showSeekBar, showProgressBar, showSubtitle,
+                    false);
         }
 
         private void setTwoLineLayout(MediaDevice device, CharSequence title, boolean bFocused,
-                boolean showSeekBar, boolean showProgressBar, boolean showSubtitle) {
+                boolean showSeekBar, boolean showProgressBar, boolean showSubtitle,
+                boolean showStatus) {
             mTitleText.setVisibility(View.GONE);
             mTwoLineLayout.setVisibility(View.VISIBLE);
+            mStatusIcon.setVisibility(showStatus ? View.VISIBLE : View.GONE);
             mSeekBar.setAlpha(1);
             mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);
+            mItemLayout.setBackground(mContext.getDrawable(R.drawable.media_output_item_background)
+                    .mutate());
             mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
             mSubTitleText.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
             mTwoLineTitleText.setTranslationY(0);
@@ -334,7 +363,7 @@
                     R.color.advanced_icon_color, mContext.getTheme());
             drawable.setColorFilter(new PorterDuffColorFilter(list.getDefaultColor(),
                     PorterDuff.Mode.SRC_IN));
-            return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
+            return drawable;
         }
 
         private void disableSeekBar() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 26ce645..91d0b49 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -20,6 +20,7 @@
 import static android.view.WindowInsets.Type.statusBars;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -64,6 +65,7 @@
     private TextView mHeaderTitle;
     private TextView mHeaderSubtitle;
     private ImageView mHeaderIcon;
+    private ImageView mAppResourceIcon;
     private RecyclerView mDevicesRecyclerView;
     private LinearLayout mDeviceListLayout;
     private Button mDoneButton;
@@ -112,6 +114,7 @@
         mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
         mDoneButton = mDialogView.requireViewById(R.id.done);
         mStopButton = mDialogView.requireViewById(R.id.stop);
+        mAppResourceIcon = mDialogView.requireViewById(R.id.app_source_icon);
 
         mDeviceListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
                 mDeviceListLayoutListener);
@@ -145,6 +148,12 @@
         // Update header icon
         final int iconRes = getHeaderIconRes();
         final IconCompat iconCompat = getHeaderIcon();
+        final Drawable appSourceDrawable = getAppSourceIcon();
+        if (appSourceDrawable != null) {
+            mAppResourceIcon.setImageDrawable(appSourceDrawable);
+        } else {
+            mAppResourceIcon.setVisibility(View.GONE);
+        }
         if (iconRes != 0) {
             mHeaderIcon.setVisibility(View.VISIBLE);
             mHeaderIcon.setImageResource(iconRes);
@@ -183,6 +192,8 @@
         mStopButton.setVisibility(getStopButtonVisibility());
     }
 
+    abstract Drawable getAppSourceIcon();
+
     abstract int getHeaderIconRes();
 
     abstract IconCompat getHeaderIcon();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 6da4d48..eef5fb0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -19,6 +19,7 @@
 import android.app.Notification;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
@@ -181,6 +182,20 @@
         mMetricLogger.logOutputFailure(mMediaDevices, reason);
     }
 
+    Drawable getAppSourceIcon() {
+        if (mPackageName.isEmpty()) {
+            return null;
+        }
+        try {
+            Log.d(TAG, "try to get app icon");
+            return mContext.getPackageManager()
+                    .getApplicationIcon(mPackageName);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.d(TAG, "icon not found");
+            return null;
+        }
+    }
+
     CharSequence getHeaderTitle() {
         if (mMediaController != null) {
             final MediaMetadata metadata = mMediaController.getMetadata();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index eca8ac9..7696a1f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -17,6 +17,7 @@
 package com.android.systemui.media.dialog;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.view.View;
 import android.view.WindowManager;
@@ -79,6 +80,11 @@
     }
 
     @Override
+    Drawable getAppSourceIcon() {
+        return mMediaOutputController.getAppSourceIcon();
+    }
+
+    @Override
     int getStopButtonVisibility() {
         return mMediaOutputController.isActiveRemoteDevice(
                 mMediaOutputController.getCurrentConnectedMediaDevice()) ? View.VISIBLE : View.GONE;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index a201c07..104ddf9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -97,7 +97,6 @@
         void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
             super.onBind(device, topMargin, bottomMargin, position);
             mAddIcon.setVisibility(View.GONE);
-            mBottomDivider.setVisibility(View.GONE);
             mCheckBox.setVisibility(View.VISIBLE);
             mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
                 onCheckBoxClicked(isChecked, device);
@@ -131,7 +130,6 @@
                         true /* bFocused */, true /* showSeekBar */, false /* showProgressBar */,
                         false /* showSubtitle*/);
                 mTitleIcon.setImageDrawable(getSpeakerDrawable());
-                mBottomDivider.setVisibility(View.VISIBLE);
                 mCheckBox.setVisibility(View.GONE);
                 mAddIcon.setVisibility(View.GONE);
                 initSessionSeekbar();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index 1300400..f1c6601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -17,6 +17,7 @@
 package com.android.systemui.media.dialog;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.view.View;
 import android.view.WindowManager;
@@ -28,6 +29,7 @@
 /**
  * Dialog for media output group.
  */
+// TODO(b/203073091): Remove this class once group logic been implemented.
 public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
 
     MediaOutputGroupDialog(Context context, boolean aboveStatusbar, MediaOutputController
@@ -76,6 +78,11 @@
     }
 
     @Override
+    Drawable getAppSourceIcon() {
+        return null;
+    }
+
+    @Override
     int getStopButtonVisibility() {
         return View.VISIBLE;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 23062d8..25337b6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -24,12 +24,15 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
+import android.inputmethodservice.InputMethodService;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.view.View;
+import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
@@ -42,12 +45,14 @@
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -69,6 +74,7 @@
         Dumpable {
     private final AccessibilityManager mAccessibilityManager;
     private final Lazy<AssistManager> mAssistManagerLazy;
+    private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
     private final UserTracker mUserTracker;
     private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
     private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
@@ -98,12 +104,14 @@
             AccessibilityButtonModeObserver accessibilityButtonModeObserver,
             OverviewProxyService overviewProxyService,
             Lazy<AssistManager> assistManagerLazy,
+            Lazy<Optional<StatusBar>> statusBarOptionalLazy,
             NavigationModeController navigationModeController,
             UserTracker userTracker,
             DumpManager dumpManager) {
         mContext = context;
         mAccessibilityManager = accessibilityManager;
         mAssistManagerLazy = assistManagerLazy;
+        mStatusBarOptionalLazy = statusBarOptionalLazy;
         mUserTracker = userTracker;
         accessibilityManagerWrapper.addCallback(
                 accessibilityManager1 -> NavBarHelper.this.dispatchA11yEventUpdate());
@@ -232,6 +240,19 @@
     }
 
     /**
+     * @return Whether the IME is shown on top of the screen given the {@code vis} flag of
+     * {@link InputMethodService} and the keyguard states.
+     */
+    public boolean isImeShown(int vis) {
+        View shadeWindowView = mStatusBarOptionalLazy.get().get().getNotificationShadeWindowView();
+        boolean isKeyguardShowing = mStatusBarOptionalLazy.get().get().isKeyguardShowing();
+        boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow()
+                && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime());
+        return imeVisibleOnShade
+                || (!isKeyguardShowing && (vis & InputMethodService.IME_VISIBLE) != 0);
+    }
+
+    /**
      * Callbacks will get fired once immediately after registering via
      * {@link #registerNavTaskStateUpdater(NavbarTaskbarStateUpdater)}
      */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 75ef8de..8026df7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -71,7 +71,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.inputmethodservice.InputMethodService;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -93,7 +92,6 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowInsetsController.Behavior;
 import android.view.WindowManager;
@@ -884,17 +882,8 @@
         if (displayId != mDisplayId) {
             return;
         }
-        boolean imeVisibleOnShade = mStatusBarOptionalLazy.get().map(statusBar -> {
-            View shadeWindowView = statusBar.getNotificationShadeWindowView();
-            return shadeWindowView.isAttachedToWindow()
-                    && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime());
-        }).orElse(false);
-        boolean isKeyguardShowing = mStatusBarOptionalLazy.get().map(
-                StatusBar::isKeyguardShowing).orElse(false);
-        boolean imeShown = imeVisibleOnShade
-                || (!isKeyguardShowing && (vis & InputMethodService.IME_VISIBLE) != 0);
+        boolean imeShown = mNavBarHelper.isImeShown(vis);
         showImeSwitcher = imeShown && showImeSwitcher;
-
         int hints = Utilities.calculateBackDispositionHints(mNavigationIconHints, backDisposition,
                 imeShown, showImeSwitcher);
         if (hints == mNavigationIconHints) return;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index fb9b8eb..8fb394c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -41,7 +41,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.hardware.display.DisplayManager;
-import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -265,7 +264,8 @@
     @Override
     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher) {
-        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
+        boolean imeShown = mNavBarHelper.isImeShown(vis);
+        showImeSwitcher = imeShown && showImeSwitcher;
         int hints = Utilities.calculateBackDispositionHints(mNavigationIconHints, backDisposition,
                 imeShown, showImeSwitcher);
         if (hints != mNavigationIconHints) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 6d1bbee..48255b5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -34,6 +34,8 @@
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DeviceControlsController;
 import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.RunningFgsController;
+import com.android.systemui.statusbar.policy.RunningFgsControllerImpl;
 import com.android.systemui.statusbar.policy.WalletController;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -89,4 +91,9 @@
     /** */
     @Binds
     QSHost provideQsHost(QSTileHost controllerImpl);
+
+    /** */
+    @Binds
+    RunningFgsController provideRunningFgsController(
+            RunningFgsControllerImpl runningFgsController);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 16be998..ac95bf5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -36,6 +36,7 @@
 import com.android.systemui.qs.tiles.DataSaverTile;
 import com.android.systemui.qs.tiles.DeviceControlsTile;
 import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.qs.tiles.FgsManagerTile;
 import com.android.systemui.qs.tiles.FlashlightTile;
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.InternetTile;
@@ -94,6 +95,7 @@
     private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider;
     private final Provider<QRCodeScannerTile> mQRCodeScannerTileProvider;
     private final Provider<OneHandedModeTile> mOneHandedModeTileProvider;
+    private final Provider<FgsManagerTile> mFgsManagerTileProvider;
 
     private final Lazy<QSHost> mQsHostLazy;
     private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -130,7 +132,8 @@
             Provider<AlarmTile> alarmTileProvider,
             Provider<QuickAccessWalletTile> quickAccessWalletTileProvider,
             Provider<QRCodeScannerTile> qrCodeScannerTileProvider,
-            Provider<OneHandedModeTile> oneHandedModeTileProvider) {
+            Provider<OneHandedModeTile> oneHandedModeTileProvider,
+            Provider<FgsManagerTile> fgsManagerTileProvider) {
         mQsHostLazy = qsHostLazy;
         mCustomTileBuilderProvider = customTileBuilderProvider;
 
@@ -163,6 +166,7 @@
         mQuickAccessWalletTileProvider = quickAccessWalletTileProvider;
         mQRCodeScannerTileProvider = qrCodeScannerTileProvider;
         mOneHandedModeTileProvider = oneHandedModeTileProvider;
+        mFgsManagerTileProvider = fgsManagerTileProvider;
     }
 
     public QSTile createTile(String tileSpec) {
@@ -233,6 +237,8 @@
                 return mQRCodeScannerTileProvider.get();
             case "onehanded":
                 return mOneHandedModeTileProvider.get();
+            case "fgsmanager":
+                return mFgsManagerTileProvider.get();
         }
 
         // Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 09fad30..eb74b1b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -652,7 +652,8 @@
         "wallet" to R.array.tile_states_wallet,
         "qr_code_scanner" to R.array.tile_states_qr_code_scanner,
         "alarm" to R.array.tile_states_alarm,
-        "onehanded" to R.array.tile_states_onehanded
+        "onehanded" to R.array.tile_states_onehanded,
+        "fgsmanager" to R.array.tile_states_fgsmanager
     )
 
     fun getSubtitleId(spec: String?): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FgsManagerTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FgsManagerTile.kt
new file mode 100644
index 0000000..75cf4d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FgsManagerTile.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 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.qs.tiles
+
+import android.content.Intent
+import android.os.Handler
+import android.os.Looper
+import android.provider.DeviceConfig
+import android.view.View
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.DejankUtils
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.fgsmanager.FgsManagerDialogFactory
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.policy.RunningFgsController
+import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * Quicksettings tile for the foreground services manager (task manager)
+ */
+class FgsManagerTile @Inject constructor(
+    host: QSHost?,
+    @Background backgroundLooper: Looper?,
+    @Background private val backgroundExecutor: Executor?,
+    @Main mainHandler: Handler?,
+    falsingManager: FalsingManager?,
+    metricsLogger: MetricsLogger?,
+    statusBarStateController: StatusBarStateController?,
+    activityStarter: ActivityStarter?,
+    qsLogger: QSLogger?,
+    private val fgsManagerDialogFactory: FgsManagerDialogFactory,
+    private val runningFgsController: RunningFgsController
+) : QSTileImpl<QSTile.State?>(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+        statusBarStateController, activityStarter, qsLogger), RunningFgsController.Callback {
+
+    override fun handleInitialize() {
+        super.handleInitialize()
+        mUiHandler.post { runningFgsController.observe(lifecycle, this) }
+    }
+
+    override fun isAvailable(): Boolean {
+        return DejankUtils.whitelistIpcs<Boolean> {
+            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+                    SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, false)
+        }
+    }
+
+    override fun newTileState(): QSTile.State {
+        return QSTile.State()
+    }
+
+    override fun handleClick(view: View?) {
+        mUiHandler.post { fgsManagerDialogFactory.create(view) }
+    }
+
+    override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
+        state?.label = tileLabel
+        state?.secondaryLabel = runningFgsController.getPackagesWithFgs().size.toString()
+        state?.handlesLongClick = false
+        state?.icon = ResourceIcon.get(R.drawable.ic_list)
+    }
+
+    override fun getMetricsCategory(): Int = 0
+
+    override fun getLongClickIntent(): Intent? = null
+
+    // Inline the string so we don't waste translator time since this isn't used in the mocks.
+    // TODO If mocks change need to remember to move this to strings.xml
+    override fun getTileLabel(): CharSequence = "Active apps"
+
+    override fun onFgsPackagesChanged(packages: List<UserPackageTime>) = refreshState()
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 6bba1ed..033fe1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -391,6 +391,8 @@
             array.recycle();
 
             mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
+            mMobileToggleDivider.setVisibility(
+                    mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 5635f65..2b5453a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -33,6 +33,7 @@
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Pair;
 import android.view.MotionEvent;
@@ -66,6 +67,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.RemoteInputView;
+import com.android.systemui.util.DumpUtilsKt;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -653,9 +655,19 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pwOriginal, String[] args) {
+        IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
+        if (mRemoteInputController != null) {
+            pw.println("mRemoteInputController: " + mRemoteInputController);
+            pw.increaseIndent();
+            mRemoteInputController.dump(pw);
+            pw.decreaseIndent();
+        }
         if (mRemoteInputListener instanceof Dumpable) {
+            pw.println("mRemoteInputListener: " + mRemoteInputListener.getClass().getSimpleName());
+            pw.increaseIndent();
             ((Dumpable) mRemoteInputListener).dump(fd, pw, args);
+            pw.decreaseIndent();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 83ef41e..00e7a03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -368,6 +368,7 @@
             // NOTE: NotificationEntry.isClearable() will internally check group children to ensure
             //  the group itself definitively clearable.
             boolean isClearable = row.getEntry().isClearable();
+            visibleTopLevelEntries++;
             if (isSilent) {
                 if (isClearable) {
                     hasClearableSilentNotifs = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index cde3b0e..31ab6bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -23,11 +23,15 @@
 import android.os.SystemProperties;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
 import android.util.Pair;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.RemoteInputView;
+import com.android.systemui.util.DumpUtilsKt;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -293,6 +297,28 @@
         mRemoteInputUriController.grantInlineReplyUriPermission(sbn, data);
     }
 
+    /** dump debug info; called by {@link NotificationRemoteInputManager} */
+    public void dump(@NonNull IndentingPrintWriter pw) {
+        pw.print("isRemoteInputActive: ");
+        pw.println(isRemoteInputActive()); // Note that this prunes the mOpen list, printed later.
+        pw.println("mOpen: " + mOpen.size());
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
+            for (Pair<WeakReference<NotificationEntry>, Object> open : mOpen) {
+                NotificationEntry entry = open.first.get();
+                pw.println(entry == null ? "???" : entry.getKey());
+            }
+        });
+        pw.println("mSpinning: " + mSpinning.size());
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
+            for (String key : mSpinning.keySet()) {
+                pw.println(key);
+            }
+        });
+        pw.println(mSpinning);
+        pw.print("mDelegate: ");
+        pw.println(mDelegate);
+    }
+
     public interface Callback {
         default void onRemoteInputActive(boolean active) {}
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index d013261..e9b7caa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -57,6 +58,7 @@
 public class BubbleCoordinator implements Coordinator {
     private static final String TAG = "BubbleCoordinator";
 
+    private final NotifPipelineFlags mNotifPipelineFlags;
     private final Optional<BubblesManager> mBubblesManagerOptional;
     private final Optional<Bubbles> mBubblesOptional;
     private final NotifCollection mNotifCollection;
@@ -66,9 +68,11 @@
 
     @Inject
     public BubbleCoordinator(
+            NotifPipelineFlags notifPipelineFlags,
             Optional<BubblesManager> bubblesManagerOptional,
             Optional<Bubbles> bubblesOptional,
             NotifCollection notifCollection) {
+        mNotifPipelineFlags = notifPipelineFlags;
         mBubblesManagerOptional = bubblesManagerOptional;
         mBubblesOptional = bubblesOptional;
         mNotifCollection = notifCollection;
@@ -130,6 +134,14 @@
                 DismissedByUserStats dismissedByUserStats,
                 int reason
         ) {
+            if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
+                // The `entry` will be from whichever pipeline is active, so if the old pipeline is
+                // running, make sure that we use the new pipeline's entry (if it still exists).
+                NotificationEntry newPipelineEntry = mNotifPipeline.getEntry(entry.getKey());
+                if (newPipelineEntry != null) {
+                    entry = newPipelineEntry;
+                }
+            }
             if (isInterceptingDismissal(entry)) {
                 mInterceptedDismissalEntries.remove(entry.getKey());
                 mOnEndDismissInterception.onEndDismissInterception(mDismissInterceptor, entry,
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 1c2b938..2fbd212 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
@@ -54,6 +54,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Pair;
@@ -3431,46 +3432,47 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pwOriginal, String[] args) {
+        IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
         // Skip super call; dump viewState ourselves
         pw.println("Notification: " + mEntry.getKey());
-        DumpUtilsKt.withIndenting(pw, ipw -> {
-            ipw.print("visibility: " + getVisibility());
-            ipw.print(", alpha: " + getAlpha());
-            ipw.print(", translation: " + getTranslation());
-            ipw.print(", removed: " + isRemoved());
-            ipw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
+            pw.print("visibility: " + getVisibility());
+            pw.print(", alpha: " + getAlpha());
+            pw.print(", translation: " + getTranslation());
+            pw.print(", removed: " + isRemoved());
+            pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
             NotificationContentView showingLayout = getShowingLayout();
-            ipw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
-            ipw.println();
-            showingLayout.dump(fd, ipw, args);
+            pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
+            pw.println();
+            showingLayout.dump(fd, pw, args);
 
             if (getViewState() != null) {
-                getViewState().dump(fd, ipw, args);
-                ipw.println();
+                getViewState().dump(fd, pw, args);
+                pw.println();
             } else {
-                ipw.println("no viewState!!!");
+                pw.println("no viewState!!!");
             }
 
             if (mIsSummaryWithChildren) {
-                ipw.println();
-                ipw.print("ChildrenContainer");
-                ipw.print(" visibility: " + mChildrenContainer.getVisibility());
-                ipw.print(", alpha: " + mChildrenContainer.getAlpha());
-                ipw.print(", translationY: " + mChildrenContainer.getTranslationY());
-                ipw.println();
+                pw.println();
+                pw.print("ChildrenContainer");
+                pw.print(" visibility: " + mChildrenContainer.getVisibility());
+                pw.print(", alpha: " + mChildrenContainer.getAlpha());
+                pw.print(", translationY: " + mChildrenContainer.getTranslationY());
+                pw.println();
                 List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
-                ipw.println("Children: " + notificationChildren.size());
-                ipw.print("{");
-                ipw.increaseIndent();
+                pw.println("Children: " + notificationChildren.size());
+                pw.print("{");
+                pw.increaseIndent();
                 for (ExpandableNotificationRow child : notificationChildren) {
-                    ipw.println();
-                    child.dump(fd, ipw, args);
+                    pw.println();
+                    child.dump(fd, pw, args);
                 }
-                ipw.decreaseIndent();
-                ipw.println("}");
+                pw.decreaseIndent();
+                pw.println("}");
             } else if (mPrivateLayout != null) {
-                mPrivateLayout.dumpSmartReplies(ipw);
+                mPrivateLayout.dumpSmartReplies(pw);
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index fa2c1ee..4b3d6f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -22,6 +22,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.IndentingPrintWriter;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -743,15 +744,16 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pwOriginal, String[] args) {
+        IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
         pw.println(getClass().getSimpleName());
-        DumpUtilsKt.withIndenting(pw, ipw -> {
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
             ExpandableViewState viewState = getViewState();
             if (viewState == null) {
-                ipw.println("no viewState!!!");
+                pw.println("no viewState!!!");
             } else {
-                viewState.dump(fd, ipw, args);
-                ipw.println();
+                viewState.dump(fd, pw, args);
+                pw.println();
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index b27a40a..e8e6e31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -20,6 +20,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.util.AttributeSet;
+import android.util.IndentingPrintWriter;
 import android.view.View;
 
 import com.android.systemui.R;
@@ -49,14 +50,15 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pwOriginal, String[] args) {
+        IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
         super.dump(fd, pw, args);
-        DumpUtilsKt.withIndenting(pw, ipw -> {
-            ipw.println("visibility: " + DumpUtilsKt.visibilityString(getVisibility()));
-            ipw.println("manageButton showHistory: " + mShowHistory);
-            ipw.println("manageButton visibility: "
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
+            pw.println("visibility: " + DumpUtilsKt.visibilityString(getVisibility()));
+            pw.println("manageButton showHistory: " + mShowHistory);
+            pw.println("manageButton visibility: "
                     + DumpUtilsKt.visibilityString(mDismissButton.getVisibility()));
-            ipw.println("dismissButton visibility: "
+            pw.println("dismissButton visibility: "
                     + DumpUtilsKt.visibilityString(mDismissButton.getVisibility()));
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ea25805..44e3718 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -47,6 +47,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.AttributeSet;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Pair;
@@ -4901,7 +4902,8 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pwOriginal, String[] args) {
+        IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
         StringBuilder sb = new StringBuilder("[")
                 .append(this.getClass().getSimpleName()).append(":")
                 .append(" pulsing=").append(mPulsing ? "T" : "f")
@@ -4915,15 +4917,15 @@
                 .append(" hideAmount=").append(mAmbientState.getHideAmount())
                 .append("]");
         pw.println(sb.toString());
-        DumpUtilsKt.withIndenting(pw, ipw -> {
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
             int childCount = getChildCount();
-            ipw.println("Number of children: " + childCount);
-            ipw.println();
+            pw.println("Number of children: " + childCount);
+            pw.println();
 
             for (int i = 0; i < childCount; i++) {
                 ExpandableView child = (ExpandableView) getChildAt(i);
-                child.dump(fd, ipw, args);
-                ipw.println();
+                child.dump(fd, pw, args);
+                pw.println();
             }
             int transientViewCount = getTransientViewCount();
             pw.println("Transient Views: " + transientViewCount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 407d287..622c45e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -72,6 +72,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.LockPatternUtils;
@@ -154,6 +155,7 @@
     private ControlsComponent mControlsComponent;
     private boolean mControlServicesAvailable = false;
 
+    @Nullable private View mAmbientIndicationArea;
     private ViewGroup mIndicationArea;
     private TextView mIndicationText;
     private TextView mIndicationTextBottom;
@@ -274,6 +276,29 @@
 
     public void initFrom(KeyguardBottomAreaView oldBottomArea) {
         setStatusBar(oldBottomArea.mStatusBar);
+
+        // if it exists, continue to use the original ambient indication container
+        // instead of the newly inflated one
+        if (mAmbientIndicationArea != null) {
+            // remove old ambient indication from its parent
+            View originalAmbientIndicationView =
+                    oldBottomArea.findViewById(R.id.ambient_indication_container);
+            ((ViewGroup) originalAmbientIndicationView.getParent())
+                    .removeView(originalAmbientIndicationView);
+
+            // remove current ambient indication from its parent (discard)
+            ViewGroup ambientIndicationParent = (ViewGroup) mAmbientIndicationArea.getParent();
+            int ambientIndicationIndex =
+                    ambientIndicationParent.indexOfChild(mAmbientIndicationArea);
+            ambientIndicationParent.removeView(mAmbientIndicationArea);
+
+            // add the old ambient indication to this view
+            ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex);
+            mAmbientIndicationArea = originalAmbientIndicationView;
+
+            // update burn-in offsets
+            dozeTimeTick();
+        }
     }
 
     @Override
@@ -288,6 +313,7 @@
         mQRCodeScannerButton = findViewById(R.id.qr_code_scanner_button);
         mControlsButton = findViewById(R.id.controls_button);
         mIndicationArea = findViewById(R.id.keyguard_indication_area);
+        mAmbientIndicationArea = findViewById(R.id.ambient_indication_container);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
@@ -923,6 +949,7 @@
         int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
                 - mBurnInYOffset;
         mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
+        mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
     }
 
     public void setAntiBurnInOffsetX(int burnInXOffset) {
@@ -931,6 +958,7 @@
         }
         mBurnInXOffset = burnInXOffset;
         mIndicationArea.setTranslationX(burnInXOffset);
+        mAmbientIndicationArea.setTranslationX(burnInXOffset);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 763984f..84ef079 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -90,6 +90,7 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Slog;
@@ -133,6 +134,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.DelegateLaunchAnimatorController;
 import com.android.systemui.assist.AssistManager;
@@ -735,6 +737,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
+            AccessibilityFloatingMenuController accessibilityFloatingMenuController,
             Lazy<AssistManager> assistManagerLazy,
             ConfigurationController configurationController,
             NotificationShadeWindowController notificationShadeWindowController,
@@ -838,6 +841,7 @@
         mVisualStabilityManager = visualStabilityManager;
         mDeviceProvisionedController = deviceProvisionedController;
         mNavigationBarController = navigationBarController;
+        mAccessibilityFloatingMenuController = accessibilityFloatingMenuController;
         mAssistManagerLazy = assistManagerLazy;
         mConfigurationController = configurationController;
         mNotificationShadeWindowController = notificationShadeWindowController;
@@ -1053,6 +1057,8 @@
         mBatteryController.observe(mLifecycle, mBatteryStateChangeCallback);
         mLifecycle.setCurrentState(RESUMED);
 
+        mAccessibilityFloatingMenuController.init();
+
         // set the initial view visibility
         int disabledFlags1 = result.mDisabledFlags1;
         int disabledFlags2 = result.mDisabledFlags2;
@@ -2292,7 +2298,8 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter pwOriginal, String[] args) {
+        IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
         synchronized (mQueueLock) {
             pw.println("Current Status Bar state:");
             pw.println("  mExpandedVisible=" + mExpandedVisible);
@@ -2333,14 +2340,12 @@
         }
         pw.println("  mStackScroller: ");
         if (mStackScroller != null) {
-            DumpUtilsKt.withIndenting(pw, ipw -> {
-                // Triple indent until we rewrite the rest of this dump()
-                ipw.increaseIndent();
-                ipw.increaseIndent();
-                mStackScroller.dump(fd, ipw, args);
-                ipw.decreaseIndent();
-                ipw.decreaseIndent();
-            });
+            // Double indent until we rewrite the rest of this dump()
+            pw.increaseIndent();
+            pw.increaseIndent();
+            mStackScroller.dump(fd, pw, args);
+            pw.decreaseIndent();
+            pw.decreaseIndent();
         }
         pw.println("  Theme:");
         String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + "";
@@ -3813,6 +3818,7 @@
     private final DeviceProvisionedController mDeviceProvisionedController;
 
     private final NavigationBarController mNavigationBarController;
+    private final AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
 
     // UI-specific methods
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 24b7b7f..33171b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -28,6 +28,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.InitController;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -185,6 +186,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
+            AccessibilityFloatingMenuController accessibilityFloatingMenuController,
             Lazy<AssistManager> assistManagerLazy,
             ConfigurationController configurationController,
             NotificationShadeWindowController notificationShadeWindowController,
@@ -287,6 +289,7 @@
                 visualStabilityManager,
                 deviceProvisionedController,
                 navigationBarController,
+                accessibilityFloatingMenuController,
                 assistManagerLazy,
                 configurationController,
                 notificationShadeWindowController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index 530da43..ef0a5b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -95,7 +95,6 @@
     private val uiEventLogger: UiEventLogger
 ) : RemoteInputViewController {
 
-    private object Token
     private val onSendListeners = ArraySet<OnSendRemoteInputListener>()
     private val resources get() = view.resources
 
@@ -179,8 +178,8 @@
 
         entry.lastRemoteInputSent = SystemClock.elapsedRealtime()
         entry.mRemoteEditImeAnimatingAway = true
-        remoteInputController.addSpinning(entry.key, Token)
-        remoteInputController.removeRemoteInput(entry, Token)
+        remoteInputController.addSpinning(entry.key, view.mToken)
+        remoteInputController.removeRemoteInput(entry, view.mToken)
         remoteInputController.remoteInputSent(entry)
         entry.setHasSentReply()
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt
new file mode 100644
index 0000000..c6dbdb1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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.policy
+
+/**
+ * Interface for tracking packages with running foreground services and demoting foreground status
+ */
+interface RunningFgsController : CallbackController<RunningFgsController.Callback> {
+
+    /**
+     * @return A list of [UserPackageTime]s which have running foreground service(s)
+     */
+    fun getPackagesWithFgs(): List<UserPackageTime>
+
+    /**
+     * Stops all foreground services running as a package
+     * @param userId the userId the package is running under
+     * @param packageName the packageName
+     */
+    fun stopFgs(userId: Int, packageName: String)
+
+    /**
+     * Returns when the list of packages with foreground services changes
+     */
+    interface Callback {
+        /**
+         * The thing that
+         * @param packages the list of packages
+         */
+        fun onFgsPackagesChanged(packages: List<UserPackageTime>)
+    }
+
+    /**
+     * A triplet <user, packageName, timeMillis> where each element is a package running
+     * under a user that has had at least one foreground service running since timeMillis.
+     * Time should be derived from [SystemClock.elapsedRealtime].
+     */
+    data class UserPackageTime(val userId: Int, val packageName: String, val startTimeMillis: Long)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
new file mode 100644
index 0000000..d44d365
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 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.policy
+
+import android.app.IActivityManager
+import android.app.IForegroundServiceObserver
+import android.os.IBinder
+import android.os.RemoteException
+import android.util.Log
+import androidx.annotation.GuardedBy
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.policy.RunningFgsController.Callback
+import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
+import com.android.systemui.util.time.SystemClock
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * Implementation for [RunningFgsController]
+ */
+@SysUISingleton
+class RunningFgsControllerImpl @Inject constructor(
+    @Background private val executor: Executor,
+    private val systemClock: SystemClock,
+    private val activityManager: IActivityManager
+) : RunningFgsController, IForegroundServiceObserver.Stub() {
+
+    companion object {
+        private val LOG_TAG = RunningFgsControllerImpl::class.java.simpleName
+    }
+
+    private val lock = Any()
+
+    @GuardedBy("lock")
+    var initialized = false
+
+    @GuardedBy("lock")
+    private val runningServiceTokens = mutableMapOf<UserPackageKey, StartTimeAndTokensValue>()
+
+    @GuardedBy("lock")
+    private val callbacks = mutableSetOf<Callback>()
+
+    fun init() {
+        synchronized(lock) {
+            if (initialized) {
+                return
+            }
+            try {
+                activityManager.registerForegroundServiceObserver(this)
+            } catch (e: RemoteException) {
+                e.rethrowFromSystemServer()
+            }
+
+            initialized = true
+        }
+    }
+
+    override fun addCallback(listener: Callback) {
+        init()
+        synchronized(lock) { callbacks.add(listener) }
+    }
+
+    override fun removeCallback(listener: Callback) {
+        init()
+        synchronized(lock) {
+            if (!callbacks.remove(listener)) {
+                Log.e(LOG_TAG, "Callback was not registered.", RuntimeException())
+            }
+        }
+    }
+
+    override fun observe(lifecycle: Lifecycle?, listener: Callback?): Callback {
+        init()
+        return super.observe(lifecycle, listener)
+    }
+
+    override fun observe(owner: LifecycleOwner?, listener: Callback?): Callback {
+        init()
+        return super.observe(owner, listener)
+    }
+
+    override fun getPackagesWithFgs(): List<UserPackageTime> {
+        init()
+        return synchronized(lock) { getPackagesWithFgsLocked() }
+    }
+
+    private fun getPackagesWithFgsLocked(): List<UserPackageTime> =
+            runningServiceTokens.map {
+                UserPackageTime(it.key.userId, it.key.packageName, it.value.fgsStartTime)
+            }
+
+    override fun stopFgs(userId: Int, packageName: String) {
+        init()
+        try {
+            activityManager.makeServicesNonForeground(packageName, userId)
+        } catch (e: RemoteException) {
+            e.rethrowFromSystemServer()
+        }
+    }
+
+    private data class UserPackageKey(
+        val userId: Int,
+        val packageName: String
+    )
+
+    private class StartTimeAndTokensValue(systemClock: SystemClock) {
+        val fgsStartTime = systemClock.elapsedRealtime()
+        var tokens = mutableSetOf<IBinder>()
+        fun addToken(token: IBinder): Boolean {
+            return tokens.add(token)
+        }
+
+        fun removeToken(token: IBinder): Boolean {
+            return tokens.remove(token)
+        }
+
+        val isEmpty: Boolean
+            get() = tokens.isEmpty()
+    }
+
+    override fun onForegroundStateChanged(
+        token: IBinder,
+        packageName: String,
+        userId: Int,
+        isForeground: Boolean
+    ) {
+        val result = synchronized(lock) {
+            val userPackageKey = UserPackageKey(userId, packageName)
+            if (isForeground) {
+                var addedNew = false
+                runningServiceTokens.getOrPut(userPackageKey) {
+                    addedNew = true
+                    StartTimeAndTokensValue(systemClock)
+                }.addToken(token)
+                if (!addedNew) {
+                    return
+                }
+            } else {
+                val startTimeAndTokensValue = runningServiceTokens[userPackageKey]
+                if (startTimeAndTokensValue?.removeToken(token) == false) {
+                    Log.e(LOG_TAG,
+                            "Stopped foreground service was not known to be running.")
+                    return
+                }
+                if (!startTimeAndTokensValue!!.isEmpty) {
+                    return
+                }
+                runningServiceTokens.remove(userPackageKey)
+            }
+            getPackagesWithFgsLocked().toList()
+        }
+
+        callbacks.forEach { executor.execute { it.onFgsPackagesChanged(result) } }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 7a664b0..a537b2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -219,6 +219,7 @@
     private void clearLayoutLineCount(View view) {
         if (view instanceof TextView) {
             ((TextView) view).nullLayouts();
+            view.forceLayout();
         }
     }
 
@@ -271,6 +272,9 @@
 
             clearLayoutLineCount(child);
             child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec);
+            if (((Button) child).getLayout() == null) {
+                Log.wtf(TAG, "Button layout is null after measure.");
+            }
 
             coveredSuggestions.add(child);
 
@@ -604,6 +608,9 @@
                 button.getPaddingLeft() + button.getPaddingRight() + textWidth
                       + getLeftCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
         button.measure(widthMeasureSpec, heightMeasureSpec);
+        if (button.getLayout() == null) {
+            Log.wtf(TAG, "Button layout is null after measure.");
+        }
 
         final int newWidth = button.getMeasuredWidth();
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
index 9f33c27..f952476 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
@@ -19,39 +19,15 @@
 import android.util.IndentingPrintWriter
 import android.view.View
 import java.io.PrintWriter
-import java.util.function.Consumer
 
 /**
- * Run some code that will print to an [IndentingPrintWriter] that wraps the given [PrintWriter].
+ * Get an [IndentingPrintWriter] which either is or wraps the given [PrintWriter].
  *
- * If the given [PrintWriter] is an [IndentingPrintWriter], the block will be passed that same
- * instance with [IndentingPrintWriter.increaseIndent] having been called, and calling
- * [IndentingPrintWriter.decreaseIndent] after completion of the block, so the passed [PrintWriter]
- * should not be used before the block completes.
+ * The original [PrintWriter] should not be used until the returned [IndentingPrintWriter] is no
+ * longer being used, to avoid inconsistent writing.
  */
-inline fun PrintWriter.withIndenting(block: (IndentingPrintWriter) -> Unit) {
-    if (this is IndentingPrintWriter) {
-        this.withIncreasedIndent { block(this) }
-    } else {
-        block(IndentingPrintWriter(this))
-    }
-}
-
-/**
- * Run some code that will print to an [IndentingPrintWriter] that wraps the given [PrintWriter].
- *
- * If the given [PrintWriter] is an [IndentingPrintWriter], the block will be passed that same
- * instance with [IndentingPrintWriter.increaseIndent] having been called, and calling
- * [IndentingPrintWriter.decreaseIndent] after completion of the block, so the passed [PrintWriter]
- * should not be used before the block completes.
- */
-fun PrintWriter.withIndenting(consumer: Consumer<IndentingPrintWriter>) {
-    if (this is IndentingPrintWriter) {
-        this.withIncreasedIndent { consumer.accept(this) }
-    } else {
-        consumer.accept(IndentingPrintWriter(this))
-    }
-}
+fun PrintWriter.asIndenting(): IndentingPrintWriter =
+    (this as? IndentingPrintWriter) ?: IndentingPrintWriter(this)
 
 /**
  * Run some code inside a block, with [IndentingPrintWriter.increaseIndent] having been called on
@@ -66,6 +42,19 @@
     }
 }
 
+/**
+ * Run some code inside a block, with [IndentingPrintWriter.increaseIndent] having been called on
+ * the given argument, and calling [IndentingPrintWriter.decreaseIndent] after completion.
+ */
+fun IndentingPrintWriter.withIncreasedIndent(runnable: Runnable) {
+    this.increaseIndent()
+    try {
+        runnable.run()
+    } finally {
+        this.decreaseIndent()
+    }
+}
+
 /** Return a readable string for the visibility */
 fun visibilityString(@View.Visibility visibility: Int): String = when (visibility) {
     View.GONE -> "gone"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index 326d902..796af11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -100,11 +100,11 @@
     @Test
     public void enableWindowMagnification_passThrough() throws RemoteException {
         mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN,
-                Float.NaN, mAnimationCallback);
+                Float.NaN, 0f, 0f, mAnimationCallback);
         waitForIdleSync();
 
         verify(mWindowMagnificationController).enableWindowMagnification(eq(3.0f),
-                eq(Float.NaN), eq(Float.NaN), eq(mAnimationCallback));
+                eq(Float.NaN), eq(Float.NaN), eq(0f), eq(0f), eq(mAnimationCallback));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
index 8bb9d42..44770fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
@@ -110,7 +110,7 @@
     }
 
     /**
-     * Sets the given window insets to the current window metics.
+     * Sets the given window insets to the current window metrics.
      *
      * @param insets the window insets.
      */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 854fc33..3cc177d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -17,22 +17,27 @@
 package com.android.systemui.accessibility;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.testing.AndroidTestingRunner;
 import android.view.SurfaceControl;
+import android.view.View;
+import android.view.WindowManager;
 import android.view.accessibility.IRemoteMagnificationAnimationCallback;
 import android.view.animation.AccelerateInterpolator;
 
@@ -40,6 +45,7 @@
 import androidx.test.filters.LargeTest;
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.model.SysUiState;
 
@@ -56,7 +62,6 @@
 
 import java.util.concurrent.atomic.AtomicReference;
 
-
 @Ignore
 @LargeTest
 @RunWith(AndroidTestingRunner.class)
@@ -74,6 +79,8 @@
     private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class);
     private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class);
     private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class);
+    private final ArgumentCaptor<Float> mOffsetXCaptor = ArgumentCaptor.forClass(Float.class);
+    private final ArgumentCaptor<Float> mOffsetYCaptor = ArgumentCaptor.forClass(Float.class);
 
     @Mock
     Handler mHandler;
@@ -94,10 +101,16 @@
     private long mWaitingAnimationPeriod;
     private long mWaitIntermediateAnimationPeriod;
 
+    private TestableWindowManager mWindowManager;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        mWindowManager = spy(new TestableWindowManager(wm));
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+
         mWaitingAnimationPeriod = 2 * ANIMATION_DURATION_MS;
         mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
         mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
@@ -119,12 +132,15 @@
             throws RemoteException {
         enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
         verifyStartValue(mScaleCaptor, 1.0f);
         verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
         verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
         verify(mAnimationCallback).onResult(true);
     }
@@ -162,8 +178,8 @@
                 });
         SystemClock.sleep(mWaitingAnimationPeriod);
 
-        verify(mSpyController).enableWindowMagnification(1, DEFAULT_CENTER_X,
-                DEFAULT_CENTER_Y);
+        verify(mSpyController).enableWindowMagnificationInternal(1, DEFAULT_CENTER_X,
+                DEFAULT_CENTER_Y, 0f, 0f);
         verify(mAnimationCallback).onResult(true);
     }
 
@@ -187,11 +203,15 @@
 
         SystemClock.sleep(mWaitingAnimationPeriod);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+                mScaleCaptor.capture(),
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
         verifyStartValue(mScaleCaptor, mCurrentScale.get());
         verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
         verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
         verify(mAnimationCallback).onResult(false);
         verify(mAnimationCallback2).onResult(true);
@@ -213,11 +233,15 @@
 
         SystemClock.sleep(mWaitingAnimationPeriod);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+                mScaleCaptor.capture(),
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
         verifyStartValue(mScaleCaptor, mCurrentScale.get());
         verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
         verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
         // It presents the window magnification is disabled.
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
 
@@ -256,7 +280,7 @@
         });
         SystemClock.sleep(mWaitingAnimationPeriod);
 
-        verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
+        verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
         verify(mAnimationCallback).onResult(false);
         verify(mAnimationCallback2).onResult(true);
@@ -286,9 +310,10 @@
         verify(mAnimationCallback).onResult(false);
         SystemClock.sleep(mWaitingAnimationPeriod);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
         //Animating in reverse, so we only check if the start values are greater than current.
         assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get());
         assertEquals(targetScale, mScaleCaptor.getValue(), 0f);
@@ -336,7 +361,7 @@
         });
         SystemClock.sleep(mWaitingAnimationPeriod);
 
-        verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
+        verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
         verify(mSpyController, never()).deleteWindowMagnification();
         verify(mAnimationCallback).onResult(false);
@@ -362,23 +387,51 @@
 
         SystemClock.sleep(mWaitingAnimationPeriod);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+                mScaleCaptor.capture(),
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
         verifyStartValue(mScaleCaptor, mCurrentScale.get());
         verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
         verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
         verify(mAnimationCallback2).onResult(true);
     }
 
     @Test
+    public void enableWindowMagnificationWithOffset_expectedValues() {
+        final float offsetRatio = -0.1f;
+        final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+        mInstrumentation.runOnMainSync(() -> {
+            Mockito.reset(mSpyController);
+            mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+                    windowBounds.exactCenterX(), windowBounds.exactCenterY(),
+                    offsetRatio, offsetRatio, mAnimationCallback);
+        });
+        SystemClock.sleep(mWaitingAnimationPeriod);
+        final View attachedView = mWindowManager.getAttachedView();
+        assertNotNull(attachedView);
+        final Rect mirrorViewBound = new Rect();
+        final View mirrorView = attachedView.findViewById(R.id.surface_view);
+        assertNotNull(mirrorView);
+        mirrorView.getBoundsOnScreen(mirrorViewBound);
+
+        assertEquals(mirrorViewBound.exactCenterX() - windowBounds.exactCenterX(),
+                Math.round(offsetRatio * mirrorViewBound.width() / 2), 0.1f);
+        assertEquals(mirrorViewBound.exactCenterY() - windowBounds.exactCenterY(),
+                Math.round(offsetRatio * mirrorViewBound.height() / 2), 0.1f);
+    }
+
+    @Test
     public void enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback()
             throws RemoteException {
         enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
 
         enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
 
-        verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
+        verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
         verify(mAnimationCallback).onResult(true);
     }
@@ -390,11 +443,15 @@
 
         deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+                mScaleCaptor.capture(),
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
         verifyStartValue(mScaleCaptor, DEFAULT_SCALE);
         verifyStartValue(mCenterXCaptor, Float.NaN);
         verifyStartValue(mCenterYCaptor, Float.NaN);
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
         verify(mAnimationCallback).onResult(true);
     }
@@ -433,8 +490,10 @@
                     mCurrentCenterY.set(mController.getCenterY());
                 });
         SystemClock.sleep(mWaitingAnimationPeriod);
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+                mScaleCaptor.capture(),
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
 
         //The animation is in verse, so we only check the start values should no be greater than
         // the current one.
@@ -442,6 +501,8 @@
         assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
         verifyStartValue(mCenterXCaptor, Float.NaN);
         verifyStartValue(mCenterYCaptor, Float.NaN);
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
         verify(mAnimationCallback).onResult(false);
         verify(mAnimationCallback2).onResult(true);
@@ -471,9 +532,13 @@
 
         deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback2);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
-                mCenterXCaptor.capture(), mCenterYCaptor.capture());
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+                mScaleCaptor.capture(),
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
         assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
         verify(mAnimationCallback).onResult(false);
         verify(mAnimationCallback2).onResult(true);
@@ -571,9 +636,18 @@
         }
 
         @Override
-        void enableWindowMagnification(float scale, float centerX, float centerY) {
-            super.enableWindowMagnification(scale, centerX, centerY);
-            mSpyController.enableWindowMagnification(scale, centerX, centerY);
+        void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
+            super.enableWindowMagnificationInternal(scale, centerX, centerY);
+            mSpyController.enableWindowMagnificationInternal(scale, centerX, centerY);
+        }
+
+        @Override
+        void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
+                float magnificationOffsetFrameRatioX, float magnificationOffsetFrameRatioY) {
+            super.enableWindowMagnificationInternal(scale, centerX, centerY,
+                    magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY);
+            mSpyController.enableWindowMagnificationInternal(scale, centerX, centerY,
+                    magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 9a30465..8fdcadd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -146,7 +146,7 @@
     @Test
     public void enableWindowMagnification_showControlAndNotifyBoundsChanged() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -159,7 +159,7 @@
     @Test
     public void enableWindowMagnification_systemGestureExclusionRectsIsSet() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         // Wait for Rects updated.
@@ -180,7 +180,7 @@
                 mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
 
         mInstrumentation.runOnMainSync(() -> {
-            controller.enableWindowMagnification(Float.NaN, Float.NaN,
+            controller.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -195,7 +195,7 @@
     @Test
     public void deleteWindowMagnification_destroyControl() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -213,7 +213,7 @@
         setSystemGestureInsets();
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     bounds.bottom);
         });
         ReferenceTestUtils.waitForCondition(this::hasMagnificationOverlapFlag);
@@ -229,7 +229,7 @@
     @Test
     public void moveMagnifier_schedulesFrame() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.moveWindowMagnifier(100f, 100f);
         });
@@ -246,8 +246,8 @@
         }).when(mHandler).postDelayed(any(Runnable.class), anyLong());
 
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnification(2.0f, Float.NaN,
-                        Float.NaN));
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(2.0f,
+                        Float.NaN, Float.NaN));
 
         mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
 
@@ -283,8 +283,8 @@
         final float displayWidth = windowBounds.width();
         final PointF magnifiedCenter = new PointF(center, center + 5f);
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, magnifiedCenter.x,
-                    magnifiedCenter.y);
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                    magnifiedCenter.x, magnifiedCenter.y);
             // Get the center again in case the center we set is out of screen.
             magnifiedCenter.set(mWindowMagnificationController.getCenterX(),
                     mWindowMagnificationController.getCenterY());
@@ -327,7 +327,7 @@
         testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
                 testWindowBounds.right + 100, testWindowBounds.bottom + 100);
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         mWindowManager.setWindowBounds(testWindowBounds);
@@ -347,7 +347,7 @@
     @Test
     public void screenSizeIsChangedToLarge_enabled_windowSizeIsConstrained() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         final int screenSize = mContext.getResources().getDimensionPixelSize(
@@ -369,7 +369,7 @@
     @Test
     public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             Mockito.reset(mWindowManager);
             Mockito.reset(mMirrorWindowControl);
@@ -398,7 +398,7 @@
     @Test
     public void initializeA11yNode_enabled_expectedValues() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
                     Float.NaN);
         });
         final View mirrorView = mWindowManager.getAttachedView();
@@ -422,7 +422,7 @@
     public void performA11yActions_visible_expectedResults() {
         final int displayId = mContext.getDisplayId();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
                     Float.NaN);
         });
 
@@ -449,7 +449,7 @@
     public void performA11yActions_visible_notifyAccessibilityActionPerformed() {
         final int displayId = mContext.getDisplayId();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
                     Float.NaN);
         });
 
@@ -462,7 +462,7 @@
     @Test
     public void enableWindowMagnification_hasA11yWindowTitle() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -473,12 +473,12 @@
     @Test
     public void enableWindowMagnificationWithScaleLessThanOne_enabled_disabled() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(0.9f, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(0.9f, Float.NaN,
                     Float.NaN);
         });
 
@@ -489,7 +489,7 @@
     public void onLocaleChanged_enabled_updateA11yWindowTitle() {
         final String newA11yWindowTitle = "new a11y window title";
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         final TestableResources testableResources = getContext().getOrCreateTestableResources();
@@ -506,7 +506,7 @@
     @Test
     public void onSingleTap_enabled_scaleIsChanged() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -530,7 +530,7 @@
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         setSystemGestureInsets();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index cdf40a1..8ca17b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -291,9 +291,12 @@
         mTargetsObserver = spy(Dependency.get(AccessibilityButtonTargetsObserver.class));
         mModeObserver = spy(Dependency.get(AccessibilityButtonModeObserver.class));
         mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
+        final AccessibilityFloatingMenuController controller =
+                new AccessibilityFloatingMenuController(mContextWrapper, mTargetsObserver,
+                        mModeObserver, mKeyguardUpdateMonitor);
+        controller.init();
 
-        return new AccessibilityFloatingMenuController(mContextWrapper, mTargetsObserver,
-                mModeObserver, mKeyguardUpdateMonitor);
+        return controller;
     }
 
     private void enableAccessibilityFloatingMenuConfig() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 52173c1..1b5e5eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -121,7 +121,6 @@
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTitleText.getText()).isEqualTo(mContext.getText(
                 R.string.media_output_dialog_pairing_new));
     }
@@ -139,7 +138,6 @@
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_SESSION_NAME);
     }
 
@@ -156,7 +154,6 @@
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(mContext.getString(
                 R.string.media_output_dialog_group));
     }
@@ -165,14 +162,13 @@
     public void onBindViewHolder_bindConnectedDevice_verifyView() {
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
 
-        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
         assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
     }
 
     @Test
@@ -199,7 +195,6 @@
         assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2);
     }
@@ -213,13 +208,10 @@
 
         assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTwoLineTitleText.getText().toString()).isEqualTo(
+        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(
                 TEST_DEVICE_NAME_2);
-        assertThat(mViewHolder.mSubTitleText.getText().toString()).isEqualTo(
-                mContext.getString(R.string.media_output_dialog_disconnected));
+        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
@@ -233,7 +225,6 @@
         assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mSubTitleText.getText()).isEqualTo(mContext.getText(
@@ -248,14 +239,13 @@
                 LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
         mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
 
-        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
         assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
+        assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
@@ -268,7 +258,6 @@
         assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 053851e..4dac6d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.media.session.MediaSessionManager;
 import android.os.Bundle;
 import android.testing.AndroidTestingRunner;
@@ -70,6 +71,7 @@
     private MediaOutputController mMediaOutputController;
     private int mHeaderIconRes;
     private IconCompat mIconCompat;
+    private Drawable mAppSourceDrawable;
     private CharSequence mHeaderTitle;
     private CharSequence mHeaderSubtitle;
 
@@ -173,6 +175,11 @@
         }
 
         @Override
+        Drawable getAppSourceIcon() {
+            return mAppSourceDrawable;
+        }
+
+        @Override
         int getHeaderIconRes() {
             return mHeaderIconRes;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 09ec4ca..d71d98e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -234,7 +235,7 @@
 
         mMediaOutputController.onRequestFailed(0 /* reason */);
 
-        verify(mCb).onRouteChanged();
+        verify(mCb, atLeastOnce()).onRouteChanged();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
index ca5d570..2c883a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
@@ -100,7 +100,6 @@
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getText()).isEqualTo(mContext.getText(
@@ -114,7 +113,6 @@
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -140,7 +138,6 @@
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -165,7 +162,6 @@
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -183,7 +179,6 @@
         assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
         assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mGroupViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index ed5b8cb..a445d6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -34,6 +35,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 
 import org.junit.Before;
@@ -42,6 +44,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 import dagger.Lazy;
 
 @RunWith(AndroidJUnit4.class)
@@ -82,8 +86,8 @@
 
         mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager,
                 mAccessibilityManagerWrapper, mAccessibilityButtonModeObserver,
-                mOverviewProxyService, mAssistManagerLazy, mNavigationModeController,
-                mUserTracker, mDumpManager);
+                mOverviewProxyService, mAssistManagerLazy, () -> Optional.of(mock(StatusBar.class)),
+                mNavigationModeController, mUserTracker, mDumpManager);
 
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index e038b6e..5003013 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -76,6 +76,7 @@
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -90,6 +91,7 @@
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
@@ -103,6 +105,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 
 import java.util.Optional;
 
@@ -135,7 +138,6 @@
     EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
     @Mock
     EdgeBackGestureHandler mEdgeBackGestureHandler;
-    @Mock
     NavBarHelper mNavBarHelper;
     @Mock
     private LightBarController mLightBarController;
@@ -179,6 +181,12 @@
         mDependency.injectTestDependency(OverviewProxyService.class, mOverviewProxyService);
         mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController);
         TestableLooper.get(this).runWithLooper(() -> {
+            mNavBarHelper = spy(new NavBarHelper(mContext, mock(AccessibilityManager.class),
+                    mock(AccessibilityManagerWrapper.class),
+                    mock(AccessibilityButtonModeObserver.class), mOverviewProxyService,
+                    () -> mock(AssistManager.class), () -> Optional.of(mStatusBar),
+                    mock(NavigationModeController.class), mock(UserTracker.class),
+                    mock(DumpManager.class)));
             mNavigationBar = createNavBar(mContext);
             mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
         });
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
index 210744e..3257a84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
@@ -47,8 +47,8 @@
 
     @Test
     fun initFrom_doesntCrash() {
-        val other = LayoutInflater.from(mContext).inflate(
-                R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
+        val other = LayoutInflater.from(mContext).inflate(R.layout.keyguard_bottom_area,
+                null, false) as KeyguardBottomAreaView
 
         other.initFrom(mKeyguardBottomArea)
         other.launchVoiceAssist()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 6625d73..a34d2f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -77,6 +77,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -219,6 +220,7 @@
     @Mock private NotificationGutsManager mNotificationGutsManager;
     @Mock private NotificationMediaManager mNotificationMediaManager;
     @Mock private NavigationBarController mNavigationBarController;
+    @Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
     @Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier;
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock private ColorExtractor.GradientColors mGradientColors;
@@ -416,6 +418,7 @@
                 mVisualStabilityManager,
                 mDeviceProvisionedController,
                 mNavigationBarController,
+                mAccessibilityFloatingMenuController,
                 () -> mAssistManager,
                 configurationController,
                 mNotificationShadeWindowController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index d36c516..526f5b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.when;
 
 import android.app.Fragment;
@@ -63,7 +62,6 @@
 import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -85,7 +83,6 @@
     // Set in instantiate()
     private StatusBarIconController mStatusBarIconController;
     private NetworkController mNetworkController;
-    private StatusBarStateController mStatusBarStateController;
     private KeyguardStateController mKeyguardStateController;
 
     private final StatusBar mStatusBar = mock(StatusBar.class);
@@ -98,7 +95,11 @@
     @Mock
     private StatusBarFragmentComponent mStatusBarFragmentComponent;
     @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
+    @Mock
+    private NotificationPanelViewController mNotificationPanelViewController;
 
     public CollapsedStatusBarFragmentTest() {
         super(CollapsedStatusBarFragment.class);
@@ -106,49 +107,35 @@
 
     @Before
     public void setup() {
-        mStatusBarStateController = mDependency
-                .injectMockDependency(StatusBarStateController.class);
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
-        when(mStatusBar.getPanelController()).thenReturn(
-                mock(NotificationPanelViewController.class));
     }
 
     @Test
-    public void testDisableNone() throws Exception {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+    public void testDisableNone() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
-        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
-                .getVisibility());
-        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock)
-                .getVisibility());
+        assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+        assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
     @Test
-    public void testDisableSystemInfo() throws Exception {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+    public void testDisableSystemInfo() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
 
-        assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
-                .getVisibility());
+        assertEquals(View.INVISIBLE, getSystemIconAreaView().getVisibility());
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
-        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
-                .getVisibility());
+        assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
     }
 
     @Test
-    public void testDisableNotifications() throws Exception {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+    public void testDisableNotifications() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
 
@@ -160,25 +147,21 @@
     }
 
     @Test
-    public void testDisableClock() throws Exception {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+    public void testDisableClock() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
 
-        assertEquals(View.GONE, mFragment.getView().findViewById(R.id.clock).getVisibility());
+        assertEquals(View.GONE, getClockView().getVisibility());
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
-        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock).getVisibility());
+        assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
     @Test
     public void disable_noOngoingCall_chipHidden() {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
 
@@ -190,9 +173,7 @@
 
     @Test
     public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
 
@@ -206,9 +187,7 @@
 
     @Test
     public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
 
@@ -221,9 +200,7 @@
 
     @Test
     public void disable_ongoingCallEnded_chipHidden() {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
 
@@ -241,56 +218,87 @@
                 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
     }
 
-    @Ignore("b/192618546")
     @Test
-    public void testOnDozingChanged() throws Exception {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
-
-        fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
-
-        Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
-
-        reset(mStatusBarStateController);
+    public void disable_isDozingButNoCustomClock_clockAndSystemInfoVisible() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         when(mStatusBarStateController.isDozing()).thenReturn(true);
+        when(mNotificationPanelViewController.hasCustomClock()).thenReturn(false);
+
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+        assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+        assertEquals(View.VISIBLE, getClockView().getVisibility());
+    }
+
+    @Test
+    public void disable_customClockButNotDozing_clockAndSystemInfoVisible() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
+
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+        assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+        assertEquals(View.VISIBLE, getClockView().getVisibility());
+    }
+
+    @Test
+    public void disable_dozingAndCustomClock_clockAndSystemInfoHidden() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+        when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
+
+        // Make sure they start out as visible
+        assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+        assertEquals(View.VISIBLE, getClockView().getVisibility());
+
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+        assertEquals(View.INVISIBLE, getSystemIconAreaView().getVisibility());
+        assertEquals(View.GONE, getClockView().getVisibility());
+    }
+
+    @Test
+    public void onDozingChanged_clockAndSystemInfoVisibilitiesUpdated() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+        when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
+
+        // Make sure they start out as visible
+        assertEquals(View.VISIBLE, getSystemIconAreaView().getVisibility());
+        assertEquals(View.VISIBLE, getClockView().getVisibility());
+
         fragment.onDozingChanged(true);
 
-        Mockito.verify(mStatusBarStateController).isDozing();
-        Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
+        // When this callback is triggered, we want to make sure the clock and system info
+        // visibilities are recalculated. Since dozing=true, they shouldn't be visible.
+        assertEquals(View.INVISIBLE, getSystemIconAreaView().getVisibility());
+        assertEquals(View.GONE, getClockView().getVisibility());
     }
 
     @Test
     public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
-
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true);
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
-        assertEquals(View.GONE, mFragment.getView().findViewById(R.id.clock).getVisibility());
+        assertEquals(View.GONE, getClockView().getVisibility());
     }
 
     @Test
     public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
-
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(false);
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
-        assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock).getVisibility());
+        assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
     @Test
     public void setUp_fragmentCreatesDaggerComponent() {
-        mFragments.dispatchResume();
-        processAllMessages();
-        CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         assertEquals(mStatusBarFragmentComponent, fragment.getStatusBarFragmentComponent());
     }
@@ -324,7 +332,7 @@
                 new StatusBarHideIconsForBouncerManager(
                         mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()),
                 mKeyguardStateController,
-                mock(NotificationPanelViewController.class),
+                mNotificationPanelViewController,
                 mNetworkController,
                 mStatusBarStateController,
                 () -> Optional.of(mStatusBar),
@@ -361,4 +369,18 @@
         when(mMockNotificationAreaController.getNotificationInnerAreaView()).thenReturn(
                 mNotificationAreaInner);
     }
+
+    private CollapsedStatusBarFragment resumeAndGetFragment() {
+        mFragments.dispatchResume();
+        processAllMessages();
+        return (CollapsedStatusBarFragment) mFragment;
+    }
+
+    private View getClockView() {
+        return mFragment.getView().findViewById(R.id.clock);
+    }
+
+    private View getSystemIconAreaView() {
+        return mFragment.getView().findViewById(R.id.system_icon_area);
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 946d22e4..86777a2 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -537,6 +537,8 @@
         // touch, we figure out what to do. If were waiting
         // we resent the delayed callback and wait again.
         mSendHoverEnterAndMoveDelayed.cancel();
+        // clear any hover events that might have been queued and never sent.
+        mSendHoverEnterAndMoveDelayed.clear();
         mSendHoverExitDelayed.cancel();
         // If a touch exploration gesture is in progress send events for its end.
         if (mState.isTouchExploring()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
index 5277425..25dcc2a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
@@ -59,15 +59,19 @@
     }
 
     boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+            float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
             @Nullable MagnificationAnimationCallback callback) {
         if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
             mTrace.logTrace(TAG + ".enableWindowMagnification",
                     FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
                     "displayId=" + displayId + ";scale=" + scale + ";centerX=" + centerX
-                    + ";centerY=" + centerY + ";callback=" + callback);
+                            + ";centerY=" + centerY + ";magnificationFrameOffsetRatioX="
+                            + magnificationFrameOffsetRatioX + ";magnificationFrameOffsetRatioY="
+                            + magnificationFrameOffsetRatioY + ";callback=" + callback);
         }
         try {
             mConnection.enableWindowMagnification(displayId, scale, centerX, centerY,
+                    magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY,
                     transformToRemoteCallback(callback, mTrace));
         } catch (RemoteException e) {
             if (DBG) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 7d8f545..820be28 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -18,6 +18,7 @@
 
 import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
 import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_UP;
 
 import static java.util.Arrays.asList;
@@ -78,6 +79,8 @@
     final DetectingState mDetectingState;
     @VisibleForTesting
     final PanningScalingGestureState mObservePanningScalingState;
+    @VisibleForTesting
+    final ViewportDraggingState mViewportDraggingState;
 
     @VisibleForTesting
     State mCurrentState;
@@ -105,6 +108,7 @@
                         policyFlags));
         mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate);
         mDetectingState = new DetectingState(context, mDetectTripleTap);
+        mViewportDraggingState = new ViewportDraggingState();
         mObservePanningScalingState = new PanningScalingGestureState(
                 new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true,
                         new PanningScalingHandler.MagnificationDelegate() {
@@ -158,7 +162,8 @@
     public void handleShortcutTriggered() {
         final Point screenSize = mTempPoint;
         getScreenSize(mTempPoint);
-        toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f);
+        toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f,
+                WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
     }
 
     private  void getScreenSize(Point outSize) {
@@ -171,14 +176,17 @@
         return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
     }
 
-    private void enableWindowMagnifier(float centerX, float centerY) {
+    private void enableWindowMagnifier(float centerX, float centerY,
+            @WindowMagnificationManager.WindowPosition int windowPosition) {
         if (DEBUG_ALL) {
-            Slog.i(mLogTag, "enableWindowMagnifier :" + centerX + ", " + centerY);
+            Slog.i(mLogTag, "enableWindowMagnifier :"
+                    + centerX + ", " + centerY + ", " + windowPosition);
         }
 
         final float scale = MathUtils.constrain(
                 mWindowMagnificationMgr.getPersistedScale(mDisplayId), MIN_SCALE, MAX_SCALE);
-        mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY);
+        mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY,
+                windowPosition);
     }
 
     private void disableWindowMagnifier() {
@@ -188,11 +196,12 @@
         mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, false);
     }
 
-    private void toggleMagnification(float centerX, float centerY) {
+    private void toggleMagnification(float centerX, float centerY,
+            @WindowMagnificationManager.WindowPosition int windowPosition) {
         if (mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)) {
             disableWindowMagnifier();
         } else {
-            enableWindowMagnifier(centerX, centerY);
+            enableWindowMagnifier(centerX, centerY, windowPosition);
         }
     }
 
@@ -200,7 +209,17 @@
         if (DEBUG_DETECTING) {
             Slog.i(mLogTag, "onTripleTap()");
         }
-        toggleMagnification(up.getX(), up.getY());
+        toggleMagnification(up.getX(), up.getY(),
+                WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
+    }
+
+    private void onTripleTapAndHold(MotionEvent up) {
+        if (DEBUG_DETECTING) {
+            Slog.i(mLogTag, "onTripleTapAndHold()");
+        }
+        enableWindowMagnifier(up.getX(), up.getY(),
+                WindowMagnificationManager.WINDOW_POSITION_AT_TOP_LEFT);
+        transitionTo(mViewportDraggingState);
     }
 
     void resetToDetectState() {
@@ -319,6 +338,65 @@
         }
     }
 
+
+    /**
+     * This class handles motion events when the event dispatcher has
+     * determined that the user is performing a single-finger drag of the
+     * magnification viewport.
+     *
+     * Leaving this state until receiving {@link MotionEvent#ACTION_UP}
+     * or {@link MotionEvent#ACTION_CANCEL}.
+     */
+    final class ViewportDraggingState implements State {
+
+        private float mLastX = Float.NaN;
+        private float mLastY = Float.NaN;
+
+        @Override
+        public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+            final int action = event.getActionMasked();
+            switch (action) {
+                case ACTION_MOVE: {
+                    if (!Float.isNaN(mLastX) && !Float.isNaN(mLastY)) {
+                        float offsetX = event.getX() - mLastX;
+                        float offsetY = event.getY() - mLastY;
+                        mWindowMagnificationMgr.moveWindowMagnification(mDisplayId, offsetX,
+                                offsetY);
+                    }
+                    mLastX = event.getX();
+                    mLastY = event.getY();
+                }
+                break;
+
+                case ACTION_UP:
+                case ACTION_CANCEL: {
+                    mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
+                    transitionTo(mDetectingState);
+                }
+                    break;
+            }
+        }
+
+        @Override
+        public void clear() {
+            mLastX = Float.NaN;
+            mLastY = Float.NaN;
+        }
+
+        @Override
+        public void onExit() {
+            clear();
+        }
+
+        @Override
+        public String toString() {
+            return "ViewportDraggingState{"
+                    + "mLastX=" + mLastX
+                    + ",mLastY=" + mLastY
+                    + '}';
+        }
+    }
+
     /**
      * This class handles motion events in a duration to determine if the user is going to
      * manipulate the window magnifier or want to interact with current UI. The rule of leaving
@@ -405,6 +483,8 @@
                 transitionTo(mObservePanningScalingState);
             } else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP) {
                 onTripleTap(motionEvent);
+            } else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP_AND_HOLD) {
+                onTripleTapAndHold(motionEvent);
             } else {
                 mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue,
                         lastDownEventTime);
@@ -439,6 +519,7 @@
         return "WindowMagnificationGestureHandler{"
                 + "mDetectingState=" + mDetectingState
                 + ", mDelegatingState=" + mDelegatingState
+                + ", mViewportDraggingState=" + mViewportDraggingState
                 + ", mMagnifiedInteractionState=" + mObservePanningScalingState
                 + ", mCurrentState=" + State.nameOf(mCurrentState)
                 + ", mPreviousState=" + State.nameOf(mPreviousState)
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index d34b4a9..9162064 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -20,12 +20,14 @@
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK;
 import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Binder;
@@ -44,6 +46,9 @@
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper}
  * create by {@link #setConnection(IWindowMagnificationConnection)}. To set the connection with
@@ -58,6 +63,25 @@
 
     private static final String TAG = "WindowMagnificationMgr";
 
+    /**
+     * Indicate that the magnification window is at the magnification center.
+     */
+    public static final int WINDOW_POSITION_AT_CENTER = 0;
+
+    /**
+     * Indicate that the magnification window is at the top-left side of the magnification
+     * center. The offset is equal to a half of MirrorSurfaceView. So, the bottom-right corner
+     * of the window is at the magnification center.
+     */
+    public static final int WINDOW_POSITION_AT_TOP_LEFT = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "WINDOW_POSITION_AT_" }, value = {
+            WINDOW_POSITION_AT_CENTER,
+            WINDOW_POSITION_AT_TOP_LEFT
+    })
+    public @interface WindowPosition {}
+
     private final Object mLock = new Object();
     private final Context mContext;
     @VisibleForTesting
@@ -281,20 +305,60 @@
     }
 
     /**
-     * Enables window magnification with specified center and scale on the specified display and
+     * Enables window magnification with specified center and scale on the given display and
      * animating the transition.
      *
      * @param displayId The logical display id.
      * @param scale The target scale, must be >= 1.
-     * @param centerX The screen-relative X coordinate around which to center,
+     * @param centerX The screen-relative X coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
-     * @param centerY The screen-relative Y coordinate around which to center,
+     * @param centerY The screen-relative Y coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
      * @param animationCallback Called when the animation result is valid.
      * @return {@code true} if the magnification is enabled successfully.
      */
     public boolean enableWindowMagnification(int displayId, float scale, float centerX,
             float centerY, @Nullable MagnificationAnimationCallback animationCallback) {
+        return enableWindowMagnification(displayId, scale, centerX, centerY, animationCallback,
+                WINDOW_POSITION_AT_CENTER);
+    }
+
+    /**
+     * Enables window magnification with specified center and scale on the given display and
+     * animating the transition.
+     *
+     * @param displayId The logical display id.
+     * @param scale The target scale, must be >= 1.
+     * @param centerX The screen-relative X coordinate around which to center for magnification,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param centerY The screen-relative Y coordinate around which to center for magnification,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param windowPosition Indicate the offset between window position and (centerX, centerY).
+     * @return {@code true} if the magnification is enabled successfully.
+     */
+    public boolean enableWindowMagnification(int displayId, float scale, float centerX,
+            float centerY, @WindowPosition int windowPosition) {
+        return enableWindowMagnification(displayId, scale, centerX, centerY,
+                STUB_ANIMATION_CALLBACK, windowPosition);
+    }
+
+    /**
+     * Enables window magnification with specified center and scale on the given display and
+     * animating the transition.
+     *
+     * @param displayId         The logical display id.
+     * @param scale             The target scale, must be >= 1.
+     * @param centerX           The screen-relative X coordinate around which to center for
+     *                          magnification, or {@link Float#NaN} to leave unchanged.
+     * @param centerY           The screen-relative Y coordinate around which to center for
+     *                          magnification, or {@link Float#NaN} to leave unchanged.
+     * @param animationCallback Called when the animation result is valid.
+     * @param windowPosition    Indicate the offset between window position and (centerX, centerY).
+     * @return {@code true} if the magnification is enabled successfully.
+     */
+    public boolean enableWindowMagnification(int displayId, float scale, float centerX,
+            float centerY, @Nullable MagnificationAnimationCallback animationCallback,
+            @WindowPosition int windowPosition) {
         final boolean enabled;
         boolean previousEnabled;
         synchronized (mLock) {
@@ -307,7 +371,7 @@
             }
             previousEnabled = magnifier.mEnabled;
             enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY,
-                    animationCallback);
+                    animationCallback, windowPosition);
         }
 
         if (enabled && !previousEnabled) {
@@ -662,6 +726,8 @@
         // The magnified bounds on the screen.
         private final Rect mSourceBounds = new Rect();
 
+        private PointF mMagnificationFrameOffsetRatio = new PointF(0f, 0f);
+
         WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
             mDisplayId = displayId;
             mWindowMagnificationManager = windowMagnificationManager;
@@ -669,14 +735,17 @@
 
         @GuardedBy("mLock")
         boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY,
-                @Nullable MagnificationAnimationCallback animationCallback) {
+                @Nullable MagnificationAnimationCallback animationCallback,
+                @WindowPosition int windowPosition) {
             // Handle defaults. The scale may be NAN when just updating magnification center.
             if (Float.isNaN(scale)) {
                 scale = getScale();
             }
             final float normScale = MagnificationScaleProvider.constrainScale(scale);
+            setMagnificationFrameOffsetRatioByWindowPosition(windowPosition);
             if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
-                    centerX, centerY, animationCallback)) {
+                    centerX, centerY, mMagnificationFrameOffsetRatio.x,
+                    mMagnificationFrameOffsetRatio.y, animationCallback)) {
                 mScale = normScale;
                 mEnabled = true;
 
@@ -685,6 +754,19 @@
             return false;
         }
 
+        void setMagnificationFrameOffsetRatioByWindowPosition(@WindowPosition int windowPosition) {
+            switch (windowPosition) {
+                case WINDOW_POSITION_AT_CENTER: {
+                    mMagnificationFrameOffsetRatio.set(0f, 0f);
+                }
+                break;
+                case WINDOW_POSITION_AT_TOP_LEFT: {
+                    mMagnificationFrameOffsetRatio.set(-1f, -1f);
+                }
+                break;
+            }
+        }
+
         @GuardedBy("mLock")
         boolean disableWindowMagnificationInternal(
                 @Nullable MagnificationAnimationCallback animationResultCallback) {
@@ -768,9 +850,15 @@
     }
 
     private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
-            float centerY, MagnificationAnimationCallback animationCallback) {
-        return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
-                displayId, scale, centerX, centerY, animationCallback);
+            float centerY, float magnificationFrameOffsetRatioX,
+            float magnificationFrameOffsetRatioY,
+            MagnificationAnimationCallback animationCallback) {
+        synchronized (mLock) {
+            return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
+                    displayId, scale, centerX, centerY,
+                    magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY,
+                    animationCallback);
+        }
     }
 
     private boolean setScaleInternal(int displayId, float scale) {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 6ac015b..f3fad84 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -18,6 +18,7 @@
 
 import android.annotation.AppIdInt;
 import android.annotation.IntDef;
+import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -108,7 +109,7 @@
     // Please note the numbers should be continuous.
     public static final int LAST_KNOWN_PACKAGE = PACKAGE_RECENTS;
 
-    @IntDef(flag = true, prefix = "RESOLVE_", value = {
+    @LongDef(flag = true, prefix = "RESOLVE_", value = {
             RESOLVE_NON_BROWSER_ONLY,
             RESOLVE_NON_RESOLVER_ONLY
     })
@@ -197,7 +198,7 @@
      * @see PackageManager#getPackageInfo(String, int)
      */
     public abstract PackageInfo getPackageInfo(String packageName,
-            @PackageInfoFlags int flags, int filterCallingUid, int userId);
+            @PackageInfoFlags long flags, int filterCallingUid, int userId);
 
     /**
      * Retrieve CE data directory inode number of an application.
@@ -226,7 +227,7 @@
      *         deleted with {@code DELETE_KEEP_DATA} flag set).
      */
     public abstract List<ApplicationInfo> getInstalledApplications(
-            @ApplicationInfoFlags int flags, @UserIdInt int userId, int callingUid);
+            @ApplicationInfoFlags long flags, @UserIdInt int userId, int callingUid);
 
     /**
      * Retrieve launcher extras for a suspended package provided to the system in
@@ -323,7 +324,7 @@
      * @see PackageManager#getPackageUidAsUser(String, int, int)
      * @return The app's uid, or < 0 if the package was not found in that user
      */
-    public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags, int userId);
+    public abstract int getPackageUid(String packageName, @PackageInfoFlags long flags, int userId);
 
     /**
      * Retrieve all of the information we know about a particular package/application.
@@ -332,7 +333,7 @@
      * @see PackageManager#getApplicationInfo(String, int)
      */
     public abstract ApplicationInfo getApplicationInfo(String packageName,
-            @ApplicationInfoFlags int flags, int filterCallingUid, int userId);
+            @ApplicationInfoFlags long flags, int filterCallingUid, int userId);
 
     /**
      * Retrieve all of the information we know about a particular activity class.
@@ -341,7 +342,7 @@
      * @see PackageManager#getActivityInfo(ComponentName, int)
      */
     public abstract ActivityInfo getActivityInfo(ComponentName component,
-            @ComponentInfoFlags int flags, int filterCallingUid, int userId);
+            @ComponentInfoFlags long flags, int filterCallingUid, int userId);
 
     /**
      * Retrieve all activities that can be performed for the given intent.
@@ -352,7 +353,7 @@
      * @see PackageManager#queryIntentActivities(Intent, int)
      */
     public abstract List<ResolveInfo> queryIntentActivities(
-            Intent intent, @Nullable String resolvedType, @ResolveInfoFlags int flags,
+            Intent intent, @Nullable String resolvedType, @ResolveInfoFlags long flags,
             int filterCallingUid, int userId);
 
 
@@ -360,14 +361,14 @@
      * Retrieve all receivers that can handle a broadcast of the given intent.
      */
     public abstract List<ResolveInfo> queryIntentReceivers(Intent intent,
-            String resolvedType, int flags, int filterCallingUid, int userId);
+            String resolvedType, @ResolveInfoFlags long flags, int filterCallingUid, int userId);
 
     /**
      * Retrieve all services that can be performed for the given intent.
      * @see PackageManager#queryIntentServices(Intent, int)
      */
     public abstract List<ResolveInfo> queryIntentServices(
-            Intent intent, int flags, int callingUid, int userId);
+            Intent intent, @ResolveInfoFlags long flags, int callingUid, int userId);
 
     /**
      * Interface to {@link com.android.server.pm.PackageManagerService#getHomeActivitiesAsUser}.
@@ -591,20 +592,20 @@
      * Resolves an activity intent, allowing instant apps to be resolved.
      */
     public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType,
-            int flags, @PrivateResolveFlags int privateResolveFlags, int userId,
+            @ResolveInfoFlags long flags, @PrivateResolveFlags long privateResolveFlags, int userId,
             boolean resolveForStart, int filterCallingUid);
 
     /**
     * Resolves a service intent, allowing instant apps to be resolved.
     */
     public abstract ResolveInfo resolveService(Intent intent, String resolvedType,
-           int flags, int userId, int callingUid);
+            @ResolveInfoFlags long flags, int userId, int callingUid);
 
     /**
     * Resolves a content provider intent.
     */
-    public abstract ProviderInfo resolveContentProvider(String name, int flags, int userId,
-            int callingUid);
+    public abstract ProviderInfo resolveContentProvider(String name, @ComponentInfoFlags long flags,
+            int userId, int callingUid);
 
     /**
      * Track the creator of a new isolated uid.
@@ -875,8 +876,8 @@
             throws IOException;
 
     /** Returns {@code true} if the specified component is enabled and matches the given flags. */
-    public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component, int flags,
-            int userId);
+    public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component,
+            @ComponentInfoFlags long flags, int userId);
 
     /** Returns {@code true} if the given user requires extra badging for icons. */
     public abstract boolean userNeedsBadging(int userId);
@@ -1024,7 +1025,7 @@
      * @param flags flags about the uninstall.
      */
     public abstract void uninstallApex(String packageName, long versionCode, int userId,
-            IntentSender intentSender, int flags);
+            IntentSender intentSender, @PackageManager.InstallFlags int installFlags);
 
     /**
      * Update fingerprint of build that updated the runtime permissions for a user.
@@ -1260,5 +1261,5 @@
     /**
      * Reconcile all app data for the given user.
      */
-    public abstract void reconcileAppsData(int userId, int flags, boolean migrateAppsData);
+    public abstract void reconcileAppsData(int userId, int storageFlags, boolean migrateAppsData);
 }
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index 7b5f2cd..259dd8ec 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -53,7 +53,7 @@
         mHandler.sendEmptyMessage(DISABLE_BUTTONS);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(ENABLE_BUTTONS), 1000);
         getContext().registerReceiver(mReceiver,
-                new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+                new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), Context.RECEIVER_EXPORTED);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 61b8ded..7341e74 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -251,7 +251,7 @@
                         "Successful background authentication!");
             }
 
-            mAlreadyDone = true;
+            markAlreadyDone();
 
             if (mTaskStackListener != null) {
                 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
@@ -327,7 +327,7 @@
             final @LockoutTracker.LockoutMode int lockoutMode =
                     handleFailedAttempt(getTargetUserId());
             if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
-                mAlreadyDone = true;
+                markAlreadyDone();
             }
 
             final CoexCoordinator coordinator = CoexCoordinator.getInstance();
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 9764a16..b73e911 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -114,7 +114,7 @@
     // Currently only used for authentication client. The cookie generated by BiometricService
     // is never 0.
     private final int mCookie;
-    boolean mAlreadyDone;
+    private boolean mAlreadyDone = false;
 
     // Use an empty callback by default since delayed operations can receive events
     // before they are started and cause NPE in subclasses that access this field directly.
@@ -202,11 +202,9 @@
         return callback;
     }
 
-    public boolean isAlreadyDone() {
-        return mAlreadyDone;
-    }
-
-    public void destroy() {
+    /** Signals this operation has completed its lifecycle and should no longer be used. */
+    void destroy() {
+        mAlreadyDone = true;
         if (mToken != null) {
             try {
                 mToken.unlinkToDeath(this, 0);
@@ -218,6 +216,20 @@
         }
     }
 
+    /**
+     * Call while the operation is still active, but nearly done, to prevent any action
+     * upon client death (only needed for authentication clients).
+     */
+    void markAlreadyDone() {
+        Slog.d(TAG, "marking operation as done: " + this);
+        mAlreadyDone = true;
+    }
+
+    /** If this operation has been marked as completely done (or cancelled). */
+    public boolean isAlreadyDone() {
+        return mAlreadyDone;
+    }
+
     @Override
     public void binderDied() {
         binderDiedInternal(true /* clearListener */);
@@ -225,10 +237,9 @@
 
     // TODO(b/157790417): Move this to the scheduler
     void binderDiedInternal(boolean clearListener) {
-        Slog.e(TAG, "Binder died, owner: " + getOwnerString()
-                + ", operation: " + this.getClass().getName());
+        Slog.e(TAG, "Binder died, operation: " + this);
 
-        if (isAlreadyDone()) {
+        if (mAlreadyDone) {
             Slog.w(TAG, "Binder died but client is finished, ignoring");
             return;
         }
@@ -299,7 +310,7 @@
     @Override
     public String toString() {
         return "{[" + mSequentialId + "] "
-                + this.getClass().getSimpleName()
+                + this.getClass().getName()
                 + ", proto=" + getProtoEnum()
                 + ", owner=" + getOwnerString()
                 + ", cookie=" + getCookie()
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 361ec40..a358bc2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -605,6 +605,9 @@
         if (operation.mState == Operation.STATE_WAITING_FOR_COOKIE) {
             Slog.w(getTag(), "Skipping cancellation for non-started operation: " + operation);
             // We can set it to null immediately, since the HAL was never notified to start.
+            if (mCurrentOperation != null) {
+                mCurrentOperation.mClientMonitor.destroy();
+            }
             mCurrentOperation = null;
             startNextOperationIfIdle();
             return;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 1c62699..a36a1a91 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1120,50 +1120,211 @@
         }
     }
 
-    private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
+    private boolean validatePackageName(int uid, String packageName) {
+        if (packageName != null) {
+            String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+            if (packageNames != null) {
+                for (String n : packageNames) {
+                    if (n.equals(packageName)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean canProjectVideo(IMediaProjection projection) {
+        if (projection != null) {
+            try {
+                if (projection.canProjectVideo()) {
+                    return true;
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to query projection service for permissions", e);
+            }
+        }
+        if (checkCallingPermission(CAPTURE_VIDEO_OUTPUT, "canProjectVideo()")) {
+            return true;
+        }
+        return canProjectSecureVideo(projection);
+    }
+
+    private boolean canProjectSecureVideo(IMediaProjection projection) {
+        if (projection != null) {
+            try {
+                if (projection.canProjectSecureVideo()) {
+                    return true;
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to query projection service for permissions", e);
+            }
+        }
+        return checkCallingPermission(CAPTURE_SECURE_VIDEO_OUTPUT, "canProjectSecureVideo()");
+    }
+
+    private boolean checkCallingPermission(String permission, String func) {
+        if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
+                + ", uid=" + Binder.getCallingUid() + " requires " + permission;
+        Slog.w(TAG, msg);
+        return false;
+    }
+
+    private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig,
+            IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
+            DisplayWindowPolicyController controller) {
+        final int callingUid = Binder.getCallingUid();
+        if (!validatePackageName(callingUid, packageName)) {
+            throw new SecurityException("packageName must match the calling uid");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("appToken must not be null");
+        }
+        if (virtualDisplayConfig == null) {
+            throw new IllegalArgumentException("virtualDisplayConfig must not be null");
+        }
+        final Surface surface = virtualDisplayConfig.getSurface();
+        int flags = virtualDisplayConfig.getFlags();
+
+        if (surface != null && surface.isSingleBuffered()) {
+            throw new IllegalArgumentException("Surface can't be single-buffered");
+        }
+
+        if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+            flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+
+            // Public displays can't be allowed to show content when locked.
+            if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
+                throw new IllegalArgumentException(
+                        "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE");
+            }
+        }
+        if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
+            flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+        }
+        if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
+            flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
+        }
+
+        if (projection != null) {
+            try {
+                if (!getProjectionService().isValidMediaProjection(projection)) {
+                    throw new SecurityException("Invalid media projection");
+                }
+                flags = projection.applyVirtualDisplayFlags(flags);
+            } catch (RemoteException e) {
+                throw new SecurityException("unable to validate media projection or flags");
+            }
+        }
+
+        if (callingUid != Process.SYSTEM_UID
+                && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
+            if (!canProjectVideo(projection)) {
+                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+                        + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
+                        + "MediaProjection token in order to create a screen sharing virtual "
+                        + "display.");
+            }
+        }
+        if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+            if (!canProjectSecureVideo(projection)) {
+                throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
+                        + "or an appropriate MediaProjection token to create a "
+                        + "secure virtual display.");
+            }
+        }
+
+        if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
+            if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+                EventLog.writeEvent(0x534e4554, "162627132", callingUid,
+                        "Attempt to create a trusted display without holding permission!");
+                throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+                        + "create a trusted virtual display.");
+            }
+        }
+
+        if (callingUid != Process.SYSTEM_UID
+                && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
+            if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+                throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+                        + "create a virtual display which is not in the default DisplayGroup.");
+            }
+        }
+
+        if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
+            flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
+        }
+
+        // Sometimes users can have sensitive information in system decoration windows. An app
+        // could create a virtual display with system decorations support and read the user info
+        // from the surface.
+        // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
+        // to trusted virtual displays.
+        final int trustedDisplayWithSysDecorFlag =
+                (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
+                        | VIRTUAL_DISPLAY_FLAG_TRUSTED);
+        if ((flags & trustedDisplayWithSysDecorFlag)
+                == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
+                && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) {
+            throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                return createVirtualDisplayLocked(callback, projection, callingUid, packageName,
+                        surface, flags, virtualDisplayConfig, controller);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private int createVirtualDisplayLocked(IVirtualDisplayCallback callback,
             IMediaProjection projection, int callingUid, String packageName, Surface surface,
             int flags, VirtualDisplayConfig virtualDisplayConfig,
             DisplayWindowPolicyController controller) {
-        synchronized (mSyncRoot) {
-            if (mVirtualDisplayAdapter == null) {
-                Slog.w(TAG, "Rejecting request to create private virtual display "
-                        + "because the virtual display adapter is not available.");
-                return -1;
-            }
-
-            DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
-                    callback, projection, callingUid, packageName, surface, flags,
-                    virtualDisplayConfig);
-            if (device == null) {
-                return -1;
-            }
-
-            // DisplayDevice events are handled manually for Virtual Displays.
-            // TODO: multi-display Fix this so that generic add/remove events are not handled in a
-            // different code path for virtual displays.  Currently this happens so that we can
-            // return a valid display ID synchronously upon successful Virtual Display creation.
-            // This code can run on any binder thread, while onDisplayDeviceAdded() callbacks are
-            // called on the DisplayThread (which we don't want to wait for?).
-            // One option would be to actually wait here on the binder thread
-            // to be notified when the virtual display is created (or failed).
-            mDisplayDeviceRepo.onDisplayDeviceEvent(device,
-                    DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
-
-            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
-            if (display != null) {
-                if (controller != null) {
-                    mDisplayWindowPolicyController.put(display.getDisplayIdLocked(), controller);
-                }
-                return display.getDisplayIdLocked();
-            }
-
-            // Something weird happened and the logical display was not created.
-            Slog.w(TAG, "Rejecting request to create virtual display "
-                    + "because the logical display was not created.");
-            mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
-            mDisplayDeviceRepo.onDisplayDeviceEvent(device,
-                    DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
+        if (mVirtualDisplayAdapter == null) {
+            Slog.w(TAG, "Rejecting request to create private virtual display "
+                    + "because the virtual display adapter is not available.");
+            return -1;
         }
+
+        DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
+                callback, projection, callingUid, packageName, surface, flags,
+                virtualDisplayConfig);
+        if (device == null) {
+            return -1;
+        }
+
+        // DisplayDevice events are handled manually for Virtual Displays.
+        // TODO: multi-display Fix this so that generic add/remove events are not handled in a
+        // different code path for virtual displays.  Currently this happens so that we can
+        // return a valid display ID synchronously upon successful Virtual Display creation.
+        // This code can run on any binder thread, while onDisplayDeviceAdded() callbacks are
+        // called on the DisplayThread (which we don't want to wait for?).
+        // One option would be to actually wait here on the binder thread
+        // to be notified when the virtual display is created (or failed).
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device,
+                DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
+
+        final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
+        if (display != null) {
+            if (controller != null) {
+                mDisplayWindowPolicyController.put(display.getDisplayIdLocked(), controller);
+            }
+            return display.getDisplayIdLocked();
+        }
+
+        // Something weird happened and the logical display was not created.
+        Slog.w(TAG, "Rejecting request to create virtual display "
+                + "because the logical display was not created.");
+        mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device,
+                DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
         return -1;
     }
 
@@ -2726,116 +2887,8 @@
         @Override // Binder call
         public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
                 IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
-            return createVirtualDisplay(virtualDisplayConfig, callback, projection, packageName,
-                    null /* controller */);
-        }
-
-        public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
-                IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
-                DisplayWindowPolicyController controller) {
-            final int callingUid = Binder.getCallingUid();
-            if (!validatePackageName(callingUid, packageName)) {
-                throw new SecurityException("packageName must match the calling uid");
-            }
-            if (callback == null) {
-                throw new IllegalArgumentException("appToken must not be null");
-            }
-            if (virtualDisplayConfig == null) {
-                throw new IllegalArgumentException("virtualDisplayConfig must not be null");
-            }
-            final Surface surface = virtualDisplayConfig.getSurface();
-            int flags = virtualDisplayConfig.getFlags();
-
-            if (surface != null && surface.isSingleBuffered()) {
-                throw new IllegalArgumentException("Surface can't be single-buffered");
-            }
-
-            if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
-                flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-
-                // Public displays can't be allowed to show content when locked.
-                if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
-                    throw new IllegalArgumentException(
-                            "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE");
-                }
-            }
-            if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
-                flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-            }
-            if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
-                flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
-            }
-
-            if (projection != null) {
-                try {
-                    if (!getProjectionService().isValidMediaProjection(projection)) {
-                        throw new SecurityException("Invalid media projection");
-                    }
-                    flags = projection.applyVirtualDisplayFlags(flags);
-                } catch (RemoteException e) {
-                    throw new SecurityException("unable to validate media projection or flags");
-                }
-            }
-
-            if (callingUid != Process.SYSTEM_UID &&
-                    (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
-                if (!canProjectVideo(projection)) {
-                    throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
-                            + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
-                            + "MediaProjection token in order to create a screen sharing virtual "
-                            + "display.");
-                }
-            }
-            if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
-                if (!canProjectSecureVideo(projection)) {
-                    throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
-                            + "or an appropriate MediaProjection token to create a "
-                            + "secure virtual display.");
-                }
-            }
-
-            if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
-                if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
-                    EventLog.writeEvent(0x534e4554, "162627132", callingUid,
-                            "Attempt to create a trusted display without holding permission!");
-                    throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
-                            + "create a trusted virtual display.");
-                }
-            }
-
-            if (callingUid != Process.SYSTEM_UID
-                    && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
-                if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
-                    throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
-                            + "create a virtual display which is not in the default DisplayGroup.");
-                }
-            }
-
-            if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
-                flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
-            }
-
-            // Sometimes users can have sensitive information in system decoration windows. An app
-            // could create a virtual display with system decorations support and read the user info
-            // from the surface.
-            // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
-            // to trusted virtual displays.
-            final int trustedDisplayWithSysDecorFlag =
-                    (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
-                            | VIRTUAL_DISPLAY_FLAG_TRUSTED);
-            if ((flags & trustedDisplayWithSysDecorFlag)
-                    == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
-                    && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) {
-                    throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
-            }
-
-            final long token = Binder.clearCallingIdentity();
-            try {
-                return createVirtualDisplayInternal(callback, projection, callingUid, packageName,
-                        surface, flags, virtualDisplayConfig, controller);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+            return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
+                    packageName, null /* controller */);
         }
 
         @Override // Binder call
@@ -3265,60 +3318,6 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
-
-        private boolean validatePackageName(int uid, String packageName) {
-            if (packageName != null) {
-                String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
-                if (packageNames != null) {
-                    for (String n : packageNames) {
-                        if (n.equals(packageName)) {
-                            return true;
-                        }
-                    }
-                }
-            }
-            return false;
-        }
-
-        private boolean canProjectVideo(IMediaProjection projection) {
-            if (projection != null) {
-                try {
-                    if (projection.canProjectVideo()) {
-                        return true;
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to query projection service for permissions", e);
-                }
-            }
-            if (checkCallingPermission(CAPTURE_VIDEO_OUTPUT, "canProjectVideo()")) {
-                return true;
-            }
-            return canProjectSecureVideo(projection);
-        }
-
-        private boolean canProjectSecureVideo(IMediaProjection projection) {
-            if (projection != null) {
-                try {
-                    if (projection.canProjectSecureVideo()){
-                        return true;
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to query projection service for permissions", e);
-                }
-            }
-            return checkCallingPermission(CAPTURE_SECURE_VIDEO_OUTPUT, "canProjectSecureVideo()");
-        }
-
-        private boolean checkCallingPermission(String permission, String func) {
-            if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
-                return true;
-            }
-            final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid() + " requires " + permission;
-            Slog.w(TAG, msg);
-            return false;
-        }
-
     }
 
     private static boolean isValidBrightness(float brightness) {
@@ -3655,6 +3654,14 @@
         }
 
         @Override
+        public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
+                IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
+                DisplayWindowPolicyController controller) {
+            return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
+                    packageName, controller);
+        }
+
+        @Override
         public DisplayWindowPolicyController getDisplayWindowPolicyController(int displayId) {
             synchronized (mSyncRoot) {
                 return mDisplayWindowPolicyController.get(displayId);
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 8460d67..1781588 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -52,8 +52,6 @@
 
     private class GnssMeasurementListenerRegistration extends GnssListenerRegistration {
 
-        private static final String GNSS_MEASUREMENTS_BUCKET = "gnss_measurement";
-
         protected GnssMeasurementListenerRegistration(
                 @Nullable GnssMeasurementRequest request,
                 CallerIdentity callerIdentity,
@@ -70,15 +68,13 @@
         @Nullable
         @Override
         protected void onActive() {
-            mLocationAttributionHelper.reportHighPowerLocationStart(
-                    getIdentity(), GNSS_MEASUREMENTS_BUCKET, getKey());
+            mLocationAttributionHelper.reportHighPowerLocationStart(getIdentity());
         }
 
         @Nullable
         @Override
         protected void onInactive() {
-            mLocationAttributionHelper.reportHighPowerLocationStop(
-                    getIdentity(), GNSS_MEASUREMENTS_BUCKET, getKey());
+            mLocationAttributionHelper.reportHighPowerLocationStop(getIdentity());
         }
     }
 
diff --git a/services/core/java/com/android/server/location/injector/LocationAttributionHelper.java b/services/core/java/com/android/server/location/injector/LocationAttributionHelper.java
index 5cb360b..4838752 100644
--- a/services/core/java/com/android/server/location/injector/LocationAttributionHelper.java
+++ b/services/core/java/com/android/server/location/injector/LocationAttributionHelper.java
@@ -24,55 +24,23 @@
 
 import android.location.util.identity.CallerIdentity;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
 
 /**
  * Helps manage appop monitoring for multiple location clients.
  */
 public class LocationAttributionHelper {
 
-    private static class BucketKey {
-        private final String mBucket;
-        private final Object mKey;
-
-        private BucketKey(String bucket, Object key) {
-            mBucket = Objects.requireNonNull(bucket);
-            mKey = Objects.requireNonNull(key);
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-
-            BucketKey that = (BucketKey) o;
-            return mBucket.equals(that.mBucket)
-                    && mKey.equals(that.mKey);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mBucket, mKey);
-        }
-    }
-
     private final AppOpsHelper mAppOpsHelper;
 
     @GuardedBy("this")
-    private final Map<CallerIdentity, Set<BucketKey>> mAttributions;
+    private final Map<CallerIdentity, Integer> mAttributions;
     @GuardedBy("this")
-    private final Map<CallerIdentity, Set<BucketKey>> mHighPowerAttributions;
+    private final Map<CallerIdentity, Integer> mHighPowerAttributions;
 
     public LocationAttributionHelper(AppOpsHelper appOpsHelper) {
         mAppOpsHelper = appOpsHelper;
@@ -84,15 +52,16 @@
     /**
      * Report normal location usage for the given caller in the given bucket, with a unique key.
      */
-    public synchronized void reportLocationStart(CallerIdentity identity, String bucket,
-            Object key) {
-        Set<BucketKey> keySet = mAttributions.computeIfAbsent(identity,
-                i -> new ArraySet<>());
-        boolean empty = keySet.isEmpty();
-        if (keySet.add(new BucketKey(bucket, key)) && empty) {
-            if (!mAppOpsHelper.startOpNoThrow(OP_MONITOR_LOCATION, identity)) {
-                mAttributions.remove(identity);
+    public synchronized void reportLocationStart(CallerIdentity identity) {
+        identity = CallerIdentity.forAggregation(identity);
+
+        int count = mAttributions.getOrDefault(identity, 0);
+        if (count == 0) {
+            if (mAppOpsHelper.startOpNoThrow(OP_MONITOR_LOCATION, identity)) {
+                mAttributions.put(identity, 1);
             }
+        } else {
+            mAttributions.put(identity, count + 1);
         }
     }
 
@@ -100,13 +69,15 @@
      * Report normal location usage has stopped for the given caller in the given bucket, with a
      * unique key.
      */
-    public synchronized void reportLocationStop(CallerIdentity identity, String bucket,
-            Object key) {
-        Set<BucketKey> keySet = mAttributions.get(identity);
-        if (keySet != null && keySet.remove(new BucketKey(bucket, key))
-                && keySet.isEmpty()) {
+    public synchronized void reportLocationStop(CallerIdentity identity) {
+        identity = CallerIdentity.forAggregation(identity);
+
+        int count = mAttributions.getOrDefault(identity, 0);
+        if (count == 1) {
             mAttributions.remove(identity);
             mAppOpsHelper.finishOp(OP_MONITOR_LOCATION, identity);
+        } else if (count > 1) {
+            mAttributions.put(identity, count - 1);
         }
     }
 
@@ -114,19 +85,19 @@
      * Report high power location usage for the given caller in the given bucket, with a unique
      * key.
      */
-    public synchronized void reportHighPowerLocationStart(CallerIdentity identity, String bucket,
-            Object key) {
-        Set<BucketKey> keySet = mHighPowerAttributions.computeIfAbsent(identity,
-                i -> new ArraySet<>());
-        boolean empty = keySet.isEmpty();
-        if (keySet.add(new BucketKey(bucket, key)) && empty) {
-            if (mAppOpsHelper.startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION, identity)) {
-                if (D) {
-                    Log.v(TAG, "starting high power location attribution for " + identity);
-                }
-            } else {
-                mHighPowerAttributions.remove(identity);
+    public synchronized void reportHighPowerLocationStart(CallerIdentity identity) {
+        identity = CallerIdentity.forAggregation(identity);
+
+        int count = mHighPowerAttributions.getOrDefault(identity, 0);
+        if (count == 0) {
+            if (D) {
+                Log.v(TAG, "starting high power location attribution for " + identity);
             }
+            if (mAppOpsHelper.startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION, identity)) {
+                mHighPowerAttributions.put(identity, 1);
+            }
+        } else {
+            mHighPowerAttributions.put(identity, count + 1);
         }
     }
 
@@ -134,16 +105,18 @@
      * Report high power location usage has stopped for the given caller in the given bucket,
      * with a unique key.
      */
-    public synchronized void reportHighPowerLocationStop(CallerIdentity identity, String bucket,
-            Object key) {
-        Set<BucketKey> keySet = mHighPowerAttributions.get(identity);
-        if (keySet != null && keySet.remove(new BucketKey(bucket, key))
-                && keySet.isEmpty()) {
+    public synchronized void reportHighPowerLocationStop(CallerIdentity identity) {
+        identity = CallerIdentity.forAggregation(identity);
+
+        int count = mHighPowerAttributions.getOrDefault(identity, 0);
+        if (count == 1) {
             if (D) {
                 Log.v(TAG, "stopping high power location attribution for " + identity);
             }
             mHighPowerAttributions.remove(identity);
             mAppOpsHelper.finishOp(OP_MONITOR_HIGH_POWER_LOCATION, identity);
+        } else if (count > 1) {
+            mHighPowerAttributions.put(identity, count - 1);
         }
     }
 }
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 17efeb3..0ce24dd 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -398,7 +398,7 @@
             EVENT_LOG.logProviderClientActive(mName, getIdentity());
 
             if (!getRequest().isHiddenFromAppOps()) {
-                mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
+                mLocationAttributionHelper.reportLocationStart(getIdentity());
             }
             onHighPowerUsageChanged();
 
@@ -413,7 +413,7 @@
 
             onHighPowerUsageChanged();
             if (!getRequest().isHiddenFromAppOps()) {
-                mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
+                mLocationAttributionHelper.reportLocationStop(getIdentity());
             }
 
             onProviderListenerInactive();
@@ -488,10 +488,10 @@
                 if (!getRequest().isHiddenFromAppOps()) {
                     if (mIsUsingHighPower) {
                         mLocationAttributionHelper.reportHighPowerLocationStart(
-                                getIdentity(), getName(), getKey());
+                                getIdentity());
                     } else {
                         mLocationAttributionHelper.reportHighPowerLocationStop(
-                                getIdentity(), getName(), getKey());
+                                getIdentity());
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/notification/VibratorHelper.java b/services/core/java/com/android/server/notification/VibratorHelper.java
index 5199ef6..be5f219 100644
--- a/services/core/java/com/android/server/notification/VibratorHelper.java
+++ b/services/core/java/com/android/server/notification/VibratorHelper.java
@@ -89,7 +89,7 @@
      */
     public void vibrate(VibrationEffect effect, AudioAttributes attrs, String reason) {
         mVibrator.vibrate(Process.SYSTEM_UID, PackageManagerService.PLATFORM_PACKAGE_NAME,
-                effect, reason, new VibrationAttributes.Builder(attrs, effect).build());
+                effect, reason, new VibrationAttributes.Builder(attrs).build());
     }
 
     /** Stop all notification vibrations (ringtone, alarm, notification usages). */
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index dca8654..6ec3405 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -318,7 +318,7 @@
     }
 
     @Nullable
-    List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags,
+    List<ResolveInfo> queryActivities(Intent intent, String resolvedType, long flags,
             int userId) {
         synchronized (mLock) {
             return mActivities.queryIntent(intent, resolvedType, flags, userId);
@@ -326,7 +326,7 @@
     }
 
     @Nullable
-    List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags,
+    List<ResolveInfo> queryActivities(Intent intent, String resolvedType, long flags,
             List<ParsedActivity> activities, int userId) {
         synchronized (mLock) {
             return mActivities.queryIntentForPackage(
@@ -335,14 +335,14 @@
     }
 
     @Nullable
-    List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, int userId) {
+    List<ResolveInfo> queryProviders(Intent intent, String resolvedType, long flags, int userId) {
         synchronized (mLock) {
             return mProviders.queryIntent(intent, resolvedType, flags, userId);
         }
     }
 
     @Nullable
-    List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags,
+    List<ResolveInfo> queryProviders(Intent intent, String resolvedType, long flags,
             List<ParsedProvider> providers, int userId) {
         synchronized (mLock) {
             return mProviders.queryIntentForPackage(intent, resolvedType, flags, providers, userId);
@@ -350,7 +350,7 @@
     }
 
     @Nullable
-    List<ProviderInfo> queryProviders(String processName, String metaDataKey, int uid, int flags,
+    List<ProviderInfo> queryProviders(String processName, String metaDataKey, int uid, long flags,
             int userId) {
         if (!sUserManager.exists(userId)) {
             return null;
@@ -409,7 +409,7 @@
     }
 
     @Nullable
-    ProviderInfo queryProvider(String authority, int flags, int userId) {
+    ProviderInfo queryProvider(String authority, long flags, int userId) {
         synchronized (mLock) {
             final ParsedProvider p = mProvidersByAuthority.get(authority);
             if (p == null) {
@@ -480,14 +480,14 @@
     }
 
     @Nullable
-    List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, int userId) {
+    List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, long flags, int userId) {
         synchronized (mLock) {
             return mReceivers.queryIntent(intent, resolvedType, flags, userId);
         }
     }
 
     @Nullable
-    List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags,
+    List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, long flags,
             List<ParsedActivity> receivers, int userId) {
         synchronized (mLock) {
             return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId);
@@ -495,14 +495,14 @@
     }
 
     @Nullable
-    List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, int userId) {
+    List<ResolveInfo> queryServices(Intent intent, String resolvedType, long flags, int userId) {
         synchronized (mLock) {
             return mServices.queryIntent(intent, resolvedType, flags, userId);
         }
     }
 
     @Nullable
-    List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags,
+    List<ResolveInfo> queryServices(Intent intent, String resolvedType, long flags,
             List<ParsedService> services, int userId) {
         synchronized (mLock) {
             return mServices.queryIntentForPackage(intent, resolvedType, flags, services, userId);
@@ -1380,7 +1380,7 @@
             return super.queryIntent(intent, resolvedType, defaultOnly, userId);
         }
 
-        List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
+        List<ResolveInfo> queryIntent(Intent intent, String resolvedType, long flags,
                 int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
@@ -1392,7 +1392,7 @@
         }
 
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<ParsedActivity> packageActivities, int userId) {
+                long flags, List<ParsedActivity> packageActivities, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
@@ -1669,7 +1669,7 @@
         // ActivityIntentResolver.
         protected final ArrayMap<ComponentName, ParsedActivity> mActivities =
                 new ArrayMap<>();
-        private int mFlags;
+        private long mFlags;
     }
 
     // Both receivers and activities share a class, but point to different get methods
@@ -1711,7 +1711,7 @@
         }
 
         @Nullable
-        List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
+        List<ResolveInfo> queryIntent(Intent intent, String resolvedType, long flags,
                 int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
@@ -1724,7 +1724,7 @@
 
         @Nullable
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<ParsedProvider> packageProviders, int userId) {
+                long flags, List<ParsedProvider> packageProviders, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
@@ -1946,7 +1946,7 @@
         }
 
         private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>();
-        private int mFlags;
+        private long mFlags;
     }
 
     private static final class ServiceIntentResolver
@@ -1969,7 +1969,7 @@
             return super.queryIntent(intent, resolvedType, defaultOnly, userId);
         }
 
-        List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
+        List<ResolveInfo> queryIntent(Intent intent, String resolvedType, long flags,
                 int userId) {
             if (!sUserManager.exists(userId)) return null;
             mFlags = flags;
@@ -1979,7 +1979,7 @@
         }
 
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<ParsedService> packageServices, int userId) {
+                long flags, List<ParsedService> packageServices, int userId) {
             if (!sUserManager.exists(userId)) return null;
             if (packageServices == null) {
                 return Collections.emptyList();
@@ -2190,7 +2190,7 @@
 
         // Keys are String (activity class name), values are Activity.
         private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>();
-        private int mFlags;
+        private long mFlags;
     }
 
     static final class InstantAppIntentResolver
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index a9df4ba..3e849f8 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -133,35 +133,36 @@
     }
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
-            int flags, @PackageManagerInternal.PrivateResolveFlags int privateResolveFlags,
+            @PackageManager.ResolveInfoFlags long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
             int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
-            int flags, int userId);
+            long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
-            int flags, int userId, int callingUid, boolean includeInstantApps);
+            long flags, int userId, int callingUid, boolean includeInstantApps);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
-            String resolvedType, int flags, int filterCallingUid, int userId,
+            String resolvedType, long flags, int filterCallingUid, int userId,
             boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
             String instantAppPkgName);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ActivityInfo getActivityInfo(ComponentName component, int flags, int userId);
+    ActivityInfo getActivityInfo(ComponentName component, long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
+    ActivityInfo getActivityInfoInternal(ComponentName component, long flags,
             int filterCallingUid, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     AndroidPackage getPackage(String packageName);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     AndroidPackage getPackage(int uid);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ApplicationInfo generateApplicationInfoFromSettings(String packageName, int flags,
+    ApplicationInfo generateApplicationInfoFromSettings(String packageName, long flags,
             int filterCallingUid, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ApplicationInfo getApplicationInfo(String packageName, int flags, int userId);
+    ApplicationInfo getApplicationInfo(String packageName, long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
+    ApplicationInfo getApplicationInfoInternal(String packageName, long flags,
             int filterCallingUid, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ComponentName getDefaultHomeActivity(int userId);
@@ -169,7 +170,7 @@
     ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
-            int flags, int sourceUserId, int parentUserId);
+            long flags, int sourceUserId, int parentUserId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     Intent getHomeIntent();
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@@ -180,11 +181,11 @@
             String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
             boolean resolveForStart, int userId, Intent intent);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    PackageInfo generatePackageInfo(PackageStateInternal ps, int flags, int userId);
+    PackageInfo generatePackageInfo(PackageStateInternal ps, long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    PackageInfo getPackageInfo(String packageName, int flags, int userId);
+    PackageInfo getPackageInfo(String packageName, long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags,
+    PackageInfo getPackageInfoInternal(String packageName, long versionCode, long flags,
             int filterCallingUid, int userId);
 
     /**
@@ -202,12 +203,12 @@
     @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     @Nullable PackageState getPackageStateCopied(@NonNull String packageName);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId);
+    ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
             int sourceUserId, int targetUserId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ServiceInfo getServiceInfo(ComponentName component, int flags, int userId);
+    ServiceInfo getServiceInfo(ComponentName component, long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     SharedLibraryInfo getSharedLibraryInfo(String name, long version);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
@@ -224,7 +225,7 @@
     boolean canViewInstantApps(int callingUid, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid, int userId,
-            int flags);
+            long flags);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isCallerSameApp(String packageName, int uid);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@@ -234,7 +235,7 @@
             @PackageManager.ComponentType int type);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
-            String resolvedType, int flags);
+            String resolvedType, long flags);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isInstantApp(String packageName, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@@ -254,18 +255,18 @@
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     int checkUidPermission(String permName, int uid);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
-    int getPackageUidInternal(String packageName, int flags, int userId, int callingUid);
+    int getPackageUidInternal(String packageName, long flags, int userId, int callingUid);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    int updateFlagsForApplication(int flags, int userId);
+    long updateFlagsForApplication(long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    int updateFlagsForComponent(int flags, int userId);
+    long updateFlagsForComponent(long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    int updateFlagsForPackage(int flags, int userId);
+    long updateFlagsForPackage(long flags, int userId);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
+    long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
             boolean isImplicitImageCaptureIntentAndNotSetByDpc);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
+    long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
             boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
@@ -291,10 +292,10 @@
     void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
-            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+            Intent intent, String resolvedType, long flags, List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
     @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags,
+    ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, long flags,
             List<ResolveInfo> query, boolean debug, int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@@ -337,7 +338,8 @@
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
-    int[] getPackageGids(@NonNull String packageName, int flags, @UserIdInt int userId);
+    int[] getPackageGids(@NonNull String packageName, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getTargetSdkVersion(@NonNull String packageName);
@@ -348,13 +350,13 @@
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
-    ActivityInfo getReceiverInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId);
+    ActivityInfo getReceiverInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
-            int flags, @UserIdInt int userId);
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
@@ -367,17 +369,18 @@
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
-            int flags, int callingUid, @UserIdInt int userId);
+            @PackageManager.PackageInfoFlags long flags, int callingUid, @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-            @NonNull String packageName, int flags, @UserIdInt int userId);
+            @NonNull String packageName, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
-    ProviderInfo getProviderInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId);
+    ProviderInfo getProviderInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
@@ -436,17 +439,17 @@
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(@NonNull String[] permissions,
-            int flags, @UserIdInt int userId);
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
-    List<ApplicationInfo> getInstalledApplications(int flags, @UserIdInt int userId,
-            int callingUid);
+    List<ApplicationInfo> getInstalledApplications(@PackageManager.ApplicationInfoFlags long flags,
+            @UserIdInt int userId, int callingUid);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
-    ProviderInfo resolveContentProvider(@NonNull String name, int flags,
-            @UserIdInt int userId, int callingUid);
+    ProviderInfo resolveContentProvider(@NonNull String name,
+            @PackageManager.ResolveInfoFlags long flags, @UserIdInt int userId, int callingUid);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
@@ -460,7 +463,7 @@
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName, int uid,
-            int flags, @Nullable String metaDataKey);
+            @PackageManager.ComponentInfoFlags long flags, @Nullable String metaDataKey);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
@@ -557,7 +560,8 @@
     boolean canQueryPackage(int callingUid, @Nullable String targetPackageName);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
-    int getPackageUid(@NonNull String packageName, int flags, @UserIdInt int userId);
+    int getPackageUid(@NonNull String packageName, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId);
 
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 887dfff..2d61773 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -125,7 +125,6 @@
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
@@ -165,7 +164,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -215,7 +213,7 @@
 
         @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
         public boolean isEnabledAndMatch(AndroidPackage pkg, ParsedMainComponent component,
-                int flags, int userId) {
+                long flags, int userId) {
             PackageStateInternal pkgState = getPackage(component.getPackageName());
             if (pkgState == null) {
                 return false;
@@ -431,8 +429,8 @@
     }
 
     public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, int flags,
-            @PackageManagerInternal.PrivateResolveFlags int privateResolveFlags,
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
             int filterCallingUid, int userId, boolean resolveForStart,
             boolean allowDynamicSplits) {
         if (!mUserManager.exists(userId)) return Collections.emptyList();
@@ -543,15 +541,15 @@
     }
 
     public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         return queryIntentActivitiesInternal(
                 intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(),
                 userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
     }
 
     public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
-            String resolvedType, int flags, int userId, int callingUid,
-            boolean includeInstantApps) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId,
+            int callingUid, boolean includeInstantApps) {
         if (!mUserManager.exists(userId)) return Collections.emptyList();
         enforceCrossUserOrProfilePermission(callingUid,
                 userId,
@@ -627,8 +625,8 @@
     }
 
     protected @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
-            String resolvedType, int flags, int userId, int callingUid,
-            String instantAppPkgName) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId,
+            int callingUid, String instantAppPkgName) {
         // reader
         String pkgName = intent.getPackage();
         if (pkgName == null) {
@@ -655,9 +653,9 @@
     }
 
     public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-            Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
-            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-            String instantAppPkgName) {
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits,
+            String pkgName, String instantAppPkgName) {
         // reader
         boolean sortResult = false;
         boolean addInstant = false;
@@ -787,7 +785,8 @@
         return null;
     }
 
-    public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+    public final ActivityInfo getActivityInfo(ComponentName component,
+            @PackageManager.ResolveInfoFlags long flags, int userId) {
         return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
     }
 
@@ -797,8 +796,8 @@
      * to clearing. Because it can only be provided by trusted code, its value can be
      * trusted and will be used as-is; unlike userId which will be validated by this method.
      */
-    public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
-            int filterCallingUid, int userId) {
+    public final ActivityInfo getActivityInfoInternal(ComponentName component,
+            @PackageManager.ResolveInfoFlags long flags, int filterCallingUid, int userId) {
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId);
 
@@ -811,8 +810,8 @@
         return getActivityInfoInternalBody(component, flags, filterCallingUid, userId);
     }
 
-    protected ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
-            int filterCallingUid, int userId) {
+    protected ActivityInfo getActivityInfoInternalBody(ComponentName component,
+            @PackageManager.ResolveInfoFlags long flags, int filterCallingUid, int userId) {
         ParsedActivity a = mComponentResolver.getActivity(component);
 
         if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
@@ -852,7 +851,7 @@
     }
 
     public final ApplicationInfo generateApplicationInfoFromSettings(String packageName,
-            int flags, int filterCallingUid, int userId) {
+            long flags, int filterCallingUid, int userId) {
         if (!mUserManager.exists(userId)) return null;
         PackageStateInternal ps = mSettings.getPackage(packageName);
         if (ps != null) {
@@ -879,7 +878,8 @@
         return null;
     }
 
-    public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+    public final ApplicationInfo getApplicationInfo(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags, int userId) {
         return getApplicationInfoInternal(packageName, flags, Binder.getCallingUid(), userId);
     }
 
@@ -889,7 +889,8 @@
      * to clearing. Because it can only be provided by trusted code, its value can be
      * trusted and will be used as-is; unlike userId which will be validated by this method.
      */
-    public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
+    public final ApplicationInfo getApplicationInfoInternal(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags,
             int filterCallingUid, int userId) {
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForApplication(flags, userId);
@@ -903,7 +904,8 @@
         return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId);
     }
 
-    protected ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
+    protected ApplicationInfo getApplicationInfoInternalBody(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags,
             int filterCallingUid, int userId) {
         // writer
         // Normalize package name to handle renamed packages and static libs
@@ -960,7 +962,7 @@
     }
 
     protected ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
-            Intent intent, int matchFlags, List<ResolveInfo> candidates,
+            Intent intent, long matchFlags, List<ResolveInfo> candidates,
             CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
         final ArrayList<ResolveInfo> result = new ArrayList<>();
         final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
@@ -1159,7 +1161,8 @@
     }
 
     public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
-            String resolvedType, int flags, int sourceUserId, int parentUserId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int sourceUserId,
+            int parentUserId) {
         if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
                 sourceUserId)) {
             return null;
@@ -1380,7 +1383,7 @@
     }
 
     private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
-            int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
+            long matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
             int userId) {
         final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
 
@@ -1423,9 +1426,8 @@
     }
 
     private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result,
-            Intent intent,
-            String resolvedType, int flags, int userId, boolean resolveForStart,
-            boolean isRequesterInstantApp) {
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            int userId, boolean resolveForStart, boolean isRequesterInstantApp) {
         // first, check to see if we've got an instant app already installed
         final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
         ResolveInfo localInstantApp = null;
@@ -1529,7 +1531,8 @@
         return result;
     }
 
-    public final PackageInfo generatePackageInfo(PackageStateInternal ps, int flags, int userId) {
+    public final PackageInfo generatePackageInfo(PackageStateInternal ps,
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         if (!mUserManager.exists(userId)) return null;
         if (ps == null) {
             return null;
@@ -1603,7 +1606,8 @@
         }
     }
 
-    public final PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+    public final PackageInfo getPackageInfo(String packageName,
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
                 flags, Binder.getCallingUid(), userId);
     }
@@ -1615,7 +1619,7 @@
      * trusted and will be used as-is; unlike userId which will be validated by this method.
      */
     public final PackageInfo getPackageInfoInternal(String packageName, long versionCode,
-            int flags, int filterCallingUid, int userId) {
+            long flags, int filterCallingUid, int userId) {
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
@@ -1626,7 +1630,7 @@
     }
 
     protected PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
-            int flags, int filterCallingUid, int userId) {
+            long flags, int filterCallingUid, int userId) {
         // reader
         // Normalize package name to handle renamed packages and static libs
         packageName = resolveInternalPackageNameLPr(packageName, versionCode);
@@ -1711,7 +1715,7 @@
         return pkgSetting == null ? null : PackageStateImpl.copy(pkgSetting);
     }
 
-    public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+    public final ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
         final int callingUid = Binder.getCallingUid();
         if (getInstantAppPackageName(callingUid) != null) {
             return ParceledListSlice.emptyList();
@@ -1725,7 +1729,7 @@
         return getInstalledPackagesBody(flags, userId, callingUid);
     }
 
-    protected ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
+    protected ParceledListSlice<PackageInfo> getInstalledPackagesBody(long flags, int userId,
             int callingUid) {
         // writer
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
@@ -1804,7 +1808,8 @@
     @Nullable
     private CrossProfileDomainInfo createForwardingResolveInfo(
             @NonNull CrossProfileIntentFilter filter, @NonNull Intent intent,
-            @Nullable String resolvedType, int flags, int sourceUserId) {
+            @Nullable String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            int sourceUserId) {
         int targetUserId = filter.getTargetUserId();
         if (!isUserEnabled(targetUserId)) {
             return null;
@@ -1891,7 +1896,7 @@
     @Nullable
     private CrossProfileDomainInfo queryCrossProfileIntents(
             List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
-            int flags, int sourceUserId, boolean matchInCurrentProfile) {
+            long flags, int sourceUserId, boolean matchInCurrentProfile) {
         if (matchingFilters == null) {
             return null;
         }
@@ -1945,7 +1950,7 @@
 
     private ResolveInfo querySkipCurrentProfileIntents(
             List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
-            int flags, int sourceUserId) {
+            long flags, int sourceUserId) {
         if (matchingFilters != null) {
             int size = matchingFilters.size();
             for (int i = 0; i < size; i++) {
@@ -1964,7 +1969,8 @@
         return null;
     }
 
-    public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+    public final ServiceInfo getServiceInfo(ComponentName component,
+            @PackageManager.ResolveInfoFlags long flags, int userId) {
         if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId);
@@ -1974,8 +1980,8 @@
         return getServiceInfoBody(component, flags, userId, callingUid);
     }
 
-    protected ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
-            int callingUid) {
+    protected ServiceInfo getServiceInfoBody(ComponentName component,
+            @PackageManager.ResolveInfoFlags long flags, int userId, int callingUid) {
         ParsedService s = mComponentResolver.getService(component);
         if (DEBUG_PACKAGE_INFO) {
             Log.v(
@@ -2227,7 +2233,7 @@
     }
 
     public final boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid,
-            int userId, int flags) {
+            int userId, @PackageManager.ComponentInfoFlags long flags) {
         // Callers can access only the libs they depend on, otherwise they need to explicitly
         // ask for the shared libraries given the caller is allowed to access all static libs.
         if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) {
@@ -2375,7 +2381,7 @@
      * activity was not set by the DPC.
      */
     public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
-            int userId, String resolvedType, int flags) {
+            int userId, String resolvedType, @PackageManager.ResolveInfoFlags long flags) {
         return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
                 intent, userId, resolvedType, flags);
     }
@@ -2416,7 +2422,7 @@
 
     private boolean isInstantAppResolutionAllowed(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-            boolean skipPackageCheck, int flags) {
+            boolean skipPackageCheck, @PackageManager.ResolveInfoFlags long flags) {
         if (mInstantAppResolverConnection == null) {
             return false;
         }
@@ -2456,7 +2462,7 @@
     // Or if there's already an ephemeral app installed that handles the action
     protected boolean isInstantAppResolutionAllowedBody(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-            boolean skipPackageCheck, int flags) {
+            boolean skipPackageCheck, @PackageManager.ResolveInfoFlags long flags) {
         final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
         for (int n = 0; n < count; n++) {
             final ResolveInfo info = resolvedActivities.get(n);
@@ -2488,7 +2494,7 @@
     }
 
     private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
-            String resolvedType, int flags) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags) {
         PersistentPreferredIntentResolver ppir =
                 mSettings.getPersistentPreferredActivities(userId);
         //TODO(b/158003772): Remove double query
@@ -2645,8 +2651,8 @@
         return mPermissionManager.checkUidPermission(uid, permName);
     }
 
-    public int getPackageUidInternal(String packageName, int flags, int userId,
-            int callingUid) {
+    public int getPackageUidInternal(String packageName,
+            @PackageManager.PackageInfoFlags long flags, int userId, int callingUid) {
         // reader
         final AndroidPackage p = mPackages.get(packageName);
         if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
@@ -2670,7 +2676,7 @@
     /**
      * Update given flags based on encryption status of current user.
      */
-    private int updateFlags(int flags, int userId) {
+    private long updateFlags(long flags, int userId) {
         if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                 | PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
             // Caller expressed an explicit opinion about what encryption
@@ -2691,21 +2697,21 @@
     /**
      * Update given flags when being used to request {@link ApplicationInfo}.
      */
-    public final int updateFlagsForApplication(int flags, int userId) {
+    public final long updateFlagsForApplication(long flags, int userId) {
         return updateFlagsForPackage(flags, userId);
     }
 
     /**
      * Update given flags when being used to request {@link ComponentInfo}.
      */
-    public final int updateFlagsForComponent(int flags, int userId) {
+    public final long updateFlagsForComponent(long flags, int userId) {
         return updateFlags(flags, userId);
     }
 
     /**
      * Update given flags when being used to request {@link PackageInfo}.
      */
-    public final int updateFlagsForPackage(int flags, int userId) {
+    public final long updateFlagsForPackage(long flags, int userId) {
         final boolean isCallerSystemUser = UserHandle.getCallingUserId()
                 == UserHandle.USER_SYSTEM;
         if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
@@ -2741,14 +2747,14 @@
      * action and a {@code android.intent.category.BROWSABLE} category</li>
      * </ul>
      */
-    public final int updateFlagsForResolve(int flags, int userId, int callingUid,
+    public final long updateFlagsForResolve(long flags, int userId, int callingUid,
             boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
         return updateFlagsForResolve(flags, userId, callingUid,
                 wantInstantApps, false /*onlyExposedExplicitly*/,
                 isImplicitImageCaptureIntentAndNotSetByDpc);
     }
 
-    public final int updateFlagsForResolve(int flags, int userId, int callingUid,
+    public final long updateFlagsForResolve(long flags, int userId, int callingUid,
             boolean wantInstantApps, boolean onlyExposedExplicitly,
             boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
         // Safe mode means we shouldn't match any third-party components
@@ -3169,7 +3175,7 @@
 
     // The body of findPreferredActivity.
     protected PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityBody(
-            Intent intent, String resolvedType, int flags,
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
             List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
             int callingUid, boolean isDeviceProvisioned) {
@@ -3378,7 +3384,7 @@
     }
 
     public final PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
-            Intent intent, String resolvedType, int flags,
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
             List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
 
@@ -3395,8 +3401,8 @@
     }
 
     public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
-            String resolvedType,
-            int flags, List<ResolveInfo> query, boolean debug, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            List<ResolveInfo> query, boolean debug, int userId) {
         final int n = query.size();
         PersistentPreferredIntentResolver ppir =
                 mSettings.getPersistentPreferredActivities(userId);
@@ -3592,7 +3598,8 @@
     }
 
     @Override
-    public int[] getPackageGids(@NonNull String packageName, int flags, @UserIdInt int userId) {
+    public int[] getPackageGids(@NonNull String packageName,
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId);
@@ -3668,8 +3675,8 @@
 
     @Nullable
     @Override
-    public ActivityInfo getReceiverInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId);
@@ -3702,7 +3709,7 @@
     @Nullable
     @Override
     public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
-            int flags, @UserIdInt int userId) {
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         if (!mUserManager.exists(userId)) return null;
         Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
         final int callingUid = Binder.getCallingUid();
@@ -3831,7 +3838,7 @@
 
     @Override
     public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
-            int flags, int callingUid, @UserIdInt int userId) {
+            @PackageManager.PackageInfoFlags long flags, int callingUid, @UserIdInt int userId) {
         List<VersionedPackage> versionedPackages = null;
         final ArrayMap<String, ? extends PackageStateInternal> packageStates = getPackageStates();
         final int packageCount = packageStates.size();
@@ -3888,7 +3895,8 @@
     @Nullable
     @Override
     public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-            @NonNull String packageName, int flags, @UserIdInt int userId) {
+            @NonNull String packageName, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_SHARED_LIBRARIES,
                 "getDeclaredSharedLibraries");
         int callingUid = Binder.getCallingUid();
@@ -3963,8 +3971,8 @@
 
     @Nullable
     @Override
-    public ProviderInfo getProviderInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ProviderInfo getProviderInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId);
@@ -4438,7 +4446,8 @@
     @NonNull
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
-            @NonNull String[] permissions, int flags, @UserIdInt int userId) {
+            @NonNull String[] permissions, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId) {
         if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
@@ -4458,7 +4467,8 @@
     }
 
     private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageStateInternal ps,
-            String[] permissions, boolean[] tmp, int flags, int userId) {
+            String[] permissions, boolean[] tmp, @PackageManager.PackageInfoFlags long flags,
+            int userId) {
         int numMatch = 0;
         for (int i=0; i<permissions.length; i++) {
             final String permission = permissions[i];
@@ -4478,7 +4488,7 @@
         // The above might return null in cases of uninstalled apps or install-state
         // skew across users/profiles.
         if (pi != null) {
-            if ((flags&PackageManager.GET_PERMISSIONS) == 0) {
+            if ((flags & PackageManager.GET_PERMISSIONS) == 0) {
                 if (numMatch == permissions.length) {
                     pi.requestedPermissions = permissions;
                 } else {
@@ -4498,7 +4508,8 @@
 
     @NonNull
     @Override
-    public List<ApplicationInfo> getInstalledApplications(int flags, @UserIdInt int userId,
+    public List<ApplicationInfo> getInstalledApplications(
+            @PackageManager.ApplicationInfoFlags long flags, @UserIdInt int userId,
             int callingUid) {
         if (getInstantAppPackageName(callingUid) != null) {
             return Collections.emptyList();
@@ -4521,7 +4532,7 @@
             list = new ArrayList<>(packageStates.size());
             for (PackageStateInternal ps : packageStates.values()) {
                 ApplicationInfo ai;
-                int effectiveFlags = flags;
+                long effectiveFlags = flags;
                 if (ps.isSystem()) {
                     effectiveFlags |= PackageManager.MATCH_ANY_USER;
                 }
@@ -4574,8 +4585,8 @@
 
     @Nullable
     @Override
-    public ProviderInfo resolveContentProvider(@NonNull String name, int flags,
-            @UserIdInt int userId, int callingUid) {
+    public ProviderInfo resolveContentProvider(@NonNull String name,
+            @PackageManager.ResolveInfoFlags long flags, @UserIdInt int userId, int callingUid) {
         if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId);
         final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
@@ -4664,7 +4675,7 @@
     @NonNull
     @Override
     public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
-            int uid, int flags, @Nullable String metaDataKey) {
+            int uid, @PackageManager.ComponentInfoFlags long flags, @Nullable String metaDataKey) {
         final int callingUid = Binder.getCallingUid();
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
@@ -5209,7 +5220,8 @@
     }
 
     @Override
-    public int getPackageUid(@NonNull String packageName, int flags, @UserIdInt int userId) {
+    public int getPackageUid(@NonNull String packageName,
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         if (!mUserManager.exists(userId)) return -1;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId);
@@ -5312,7 +5324,7 @@
             if (parent == null) {
                 return false;
             }
-            int flags = updateFlagsForResolve(0, parent.id, callingUid,
+            long flags = updateFlagsForResolve(0, parent.id, callingUid,
                     false /*includeInstantApps*/,
                     isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
                             resolvedType, 0));
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index 801aaef..f180d19 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -29,6 +29,7 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.KeySet;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ProcessInfo;
 import android.content.pm.ProviderInfo;
@@ -89,7 +90,7 @@
         }
     }
     public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-            Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
+            Intent intent, String resolvedType, long flags, int filterCallingUid, int userId,
             boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
             String instantAppPkgName) {
         synchronized (mLock) {
@@ -312,7 +313,8 @@
     }
 
     @Override
-    public int[] getPackageGids(@NonNull String packageName, int flags, @UserIdInt int userId) {
+    public int[] getPackageGids(@NonNull String packageName,
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getPackageGids(packageName, flags, userId);
         }
@@ -336,8 +338,8 @@
 
     @Nullable
     @Override
-    public ActivityInfo getReceiverInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getReceiverInfo(component, flags, userId);
         }
@@ -346,7 +348,7 @@
     @Nullable
     @Override
     public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
-            int flags, @UserIdInt int userId) {
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getSharedLibraries(packageName, flags, userId);
         }
@@ -363,7 +365,7 @@
 
     @Override
     public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
-            int flags, int callingUid, @UserIdInt int userId) {
+            @PackageManager.PackageInfoFlags long flags, int callingUid, @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
         }
@@ -372,7 +374,8 @@
     @Nullable
     @Override
     public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-            @NonNull String packageName, int flags, @UserIdInt int userId) {
+            @NonNull String packageName, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getDeclaredSharedLibraries(packageName, flags, userId);
         }
@@ -380,8 +383,8 @@
 
     @Nullable
     @Override
-    public ProviderInfo getProviderInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ProviderInfo getProviderInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getProviderInfo(component, flags, userId);
         }
@@ -495,7 +498,8 @@
     @NonNull
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
-            @NonNull String[] permissions, int flags, @UserIdInt int userId) {
+            @NonNull String[] permissions, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getPackagesHoldingPermissions(permissions, flags, userId);
         }
@@ -503,7 +507,8 @@
 
     @NonNull
     @Override
-    public List<ApplicationInfo> getInstalledApplications(int flags, @UserIdInt int userId,
+    public List<ApplicationInfo> getInstalledApplications(
+            @PackageManager.ApplicationInfoFlags long flags, @UserIdInt int userId,
             int callingUid) {
         synchronized (mLock) {
             return super.getInstalledApplications(flags, userId, callingUid);
@@ -512,8 +517,8 @@
 
     @Nullable
     @Override
-    public ProviderInfo resolveContentProvider(@NonNull String name, int flags,
-            @UserIdInt int userId, int callingUid) {
+    public ProviderInfo resolveContentProvider(@NonNull String name,
+            @PackageManager.ResolveInfoFlags long flags, @UserIdInt int userId, int callingUid) {
         synchronized (mLock) {
             return super.resolveContentProvider(name, flags, userId, callingUid);
         }
@@ -539,7 +544,7 @@
     @NonNull
     @Override
     public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
-            int uid, int flags, @Nullable String metaDataKey) {
+            int uid, @PackageManager.ComponentInfoFlags long flags, @Nullable String metaDataKey) {
         synchronized (mLock) {
             return super.queryContentProviders(processName, uid, flags, metaDataKey);
         }
@@ -711,7 +716,8 @@
     }
 
     @Override
-    public int getPackageUid(@NonNull String packageName, int flags, @UserIdInt int userId) {
+    public int getPackageUid(@NonNull String packageName,
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         synchronized (mLock) {
             return super.getPackageUid(packageName, flags, userId);
         }
diff --git a/services/core/java/com/android/server/pm/ComputerTracker.java b/services/core/java/com/android/server/pm/ComputerTracker.java
index ca17d66..a3cd092 100644
--- a/services/core/java/com/android/server/pm/ComputerTracker.java
+++ b/services/core/java/com/android/server/pm/ComputerTracker.java
@@ -97,8 +97,8 @@
     }
 
     public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, int flags,
-            @PackageManagerInternal.PrivateResolveFlags int privateResolveFlags,
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
             int filterCallingUid, int userId, boolean resolveForStart,
             boolean allowDynamicSplits) {
         ThreadComputer current = snapshot();
@@ -111,7 +111,7 @@
         }
     }
     public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         ThreadComputer current = snapshot();
         try {
             return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
@@ -121,8 +121,8 @@
         }
     }
     public @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
-            String resolvedType, int flags, int userId, int callingUid,
-            boolean includeInstantApps) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId,
+            int callingUid, boolean includeInstantApps) {
         ThreadComputer current = snapshot();
         try {
             return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags,
@@ -132,10 +132,9 @@
         }
     }
     public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-            Intent intent,
-            String resolvedType, int flags, int filterCallingUid, int userId,
-            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-            String instantAppPkgName) {
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits,
+            String pkgName, String instantAppPkgName) {
         ThreadComputer current = live();
         try {
             return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType,
@@ -145,7 +144,8 @@
             current.release();
         }
     }
-    public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+    public ActivityInfo getActivityInfo(ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, int userId) {
         ThreadComputer current = snapshot();
         try {
             return current.mComputer.getActivityInfo(component, flags, userId);
@@ -153,7 +153,8 @@
             current.release();
         }
     }
-    public ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
+    public ActivityInfo getActivityInfoInternal(ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags,
             int filterCallingUid, int userId) {
         ThreadComputer current = live();
         try {
@@ -180,7 +181,7 @@
         }
     }
     public ApplicationInfo generateApplicationInfoFromSettings(String packageName,
-            int flags, int filterCallingUid, int userId) {
+            long flags, int filterCallingUid, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.generateApplicationInfoFromSettings(packageName, flags,
@@ -189,7 +190,8 @@
             current.release();
         }
     }
-    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+    public ApplicationInfo getApplicationInfo(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags, int userId) {
         ThreadComputer current = snapshot();
         try {
             return current.mComputer.getApplicationInfo(packageName, flags, userId);
@@ -197,8 +199,8 @@
             current.release();
         }
     }
-    public ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
-            int filterCallingUid, int userId) {
+    public ApplicationInfo getApplicationInfoInternal(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags, int filterCallingUid, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.getApplicationInfoInternal(packageName, flags,
@@ -225,7 +227,8 @@
         }
     }
     public CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
-            String resolvedType, int flags, int sourceUserId, int parentUserId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int sourceUserId,
+            int parentUserId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType,
@@ -264,7 +267,8 @@
             current.release();
         }
     }
-    public PackageInfo generatePackageInfo(PackageStateInternal ps, int flags, int userId) {
+    public PackageInfo generatePackageInfo(PackageStateInternal ps,
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.generatePackageInfo(ps, flags, userId);
@@ -272,7 +276,8 @@
             current.release();
         }
     }
-    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+    public PackageInfo getPackageInfo(String packageName,
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         ThreadComputer current = snapshot();
         try {
             return current.mComputer.getPackageInfo(packageName, flags, userId);
@@ -281,7 +286,7 @@
         }
     }
     public PackageInfo getPackageInfoInternal(String packageName, long versionCode,
-            int flags, int filterCallingUid, int userId) {
+            long flags, int filterCallingUid, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags,
@@ -317,7 +322,7 @@
         }
     }
 
-    public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+    public ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
         ThreadComputer current = snapshot();
         try {
             return current.mComputer.getInstalledPackages(flags, userId);
@@ -335,7 +340,8 @@
             current.release();
         }
     }
-    public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+    public ServiceInfo getServiceInfo(ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.getServiceInfo(component, flags, userId);
@@ -440,7 +446,7 @@
         }
     }
     public boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid,
-            int userId, int flags) {
+            int userId, @PackageManager.ComponentInfoFlags long flags) {
         ThreadComputer current = live();
         try {
             return current.mComputer.filterSharedLibPackage(ps, uid, userId, flags);
@@ -474,7 +480,7 @@
         }
     }
     public boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
-            int userId, String resolvedType, int flags) {
+            int userId, String resolvedType, @PackageManager.ResolveInfoFlags long flags) {
         ThreadComputer current = live();
         try {
             return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent,
@@ -546,8 +552,8 @@
             current.release();
         }
     }
-    public int getPackageUidInternal(String packageName, int flags, int userId,
-            int callingUid) {
+    public int getPackageUidInternal(String packageName,
+            @PackageManager.PackageInfoFlags long flags, int userId, int callingUid) {
         ThreadComputer current = live();
         try {
             return current.mComputer.getPackageUidInternal(packageName, flags, userId,
@@ -556,7 +562,7 @@
             current.release();
         }
     }
-    public int updateFlagsForApplication(int flags, int userId) {
+    public long updateFlagsForApplication(long flags, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.updateFlagsForApplication(flags, userId);
@@ -564,7 +570,7 @@
             current.release();
         }
     }
-    public int updateFlagsForComponent(int flags, int userId) {
+    public long updateFlagsForComponent(long flags, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.updateFlagsForComponent(flags, userId);
@@ -572,7 +578,7 @@
             current.release();
         }
     }
-    public int updateFlagsForPackage(int flags, int userId) {
+    public long updateFlagsForPackage(long flags, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.updateFlagsForPackage(flags, userId);
@@ -580,7 +586,7 @@
             current.release();
         }
     }
-    public int updateFlagsForResolve(int flags, int userId, int callingUid,
+    public long updateFlagsForResolve(long flags, int userId, int callingUid,
             boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
         ThreadComputer current = snapshot();
         try {
@@ -590,7 +596,7 @@
             current.release();
         }
     }
-    public int updateFlagsForResolve(int flags, int userId, int callingUid,
+    public long updateFlagsForResolve(long flags, int userId, int callingUid,
             boolean wantInstantApps, boolean onlyExposedExplicitly,
             boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
         ThreadComputer current = live();
@@ -642,8 +648,9 @@
         }
     }
     public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
-            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
-            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
+            int userId, boolean queryMayBeFiltered) {
         ThreadComputer current = live();
         try {
             return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
@@ -653,8 +660,8 @@
         }
     }
     public ResolveInfo findPersistentPreferredActivityLP(Intent intent,
-            String resolvedType, int flags, List<ResolveInfo> query, boolean debug,
-            int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            List<ResolveInfo> query, boolean debug, int userId) {
         ThreadComputer current = live();
         try {
             return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
@@ -741,7 +748,8 @@
     }
 
     @Override
-    public int[] getPackageGids(@NonNull String packageName, int flags, @UserIdInt int userId) {
+    public int[] getPackageGids(@NonNull String packageName,
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getPackageGids(packageName, flags, userId);
         }
@@ -765,8 +773,8 @@
 
     @Nullable
     @Override
-    public ActivityInfo getReceiverInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getReceiverInfo(component, flags, userId);
         }
@@ -775,7 +783,7 @@
     @Nullable
     @Override
     public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
-            int flags, @UserIdInt int userId) {
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getSharedLibraries(packageName, flags, userId);
         }
@@ -800,7 +808,7 @@
 
     @Override
     public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
-            int flags, int callingUid, @UserIdInt int userId) {
+            @PackageManager.PackageInfoFlags long flags, int callingUid, @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid,
                     userId);
@@ -810,7 +818,8 @@
     @Nullable
     @Override
     public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-            @NonNull String packageName, int flags, @UserIdInt int userId) {
+            @NonNull String packageName, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
         }
@@ -818,8 +827,8 @@
 
     @Nullable
     @Override
-    public ProviderInfo getProviderInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ProviderInfo getProviderInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getProviderInfo(component, flags, userId);
         }
@@ -934,7 +943,8 @@
     @NonNull
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
-            @NonNull String[] permissions, int flags, @UserIdInt int userId) {
+            @NonNull String[] permissions, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
         }
@@ -942,7 +952,8 @@
 
     @NonNull
     @Override
-    public List<ApplicationInfo> getInstalledApplications(int flags, @UserIdInt int userId,
+    public List<ApplicationInfo> getInstalledApplications(
+            @PackageManager.ApplicationInfoFlags long flags, @UserIdInt int userId,
             int callingUid) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getInstalledApplications(flags, userId, callingUid);
@@ -951,8 +962,8 @@
 
     @Nullable
     @Override
-    public ProviderInfo resolveContentProvider(@NonNull String name, int flags,
-            @UserIdInt int userId, int callingUid) {
+    public ProviderInfo resolveContentProvider(@NonNull String name,
+            @PackageManager.ResolveInfoFlags long flags, @UserIdInt int userId, int callingUid) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.resolveContentProvider(name, flags, userId, callingUid);
         }
@@ -979,7 +990,7 @@
     @NonNull
     @Override
     public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
-            int uid, int flags, @Nullable String metaDataKey) {
+            int uid, @PackageManager.ComponentInfoFlags long flags, @Nullable String metaDataKey) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
         }
@@ -1152,7 +1163,8 @@
     }
 
     @Override
-    public int getPackageUid(@NonNull String packageName, int flags, @UserIdInt int userId) {
+    public int getPackageUid(@NonNull String packageName,
+            @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
             return current.mComputer.getPackageUid(packageName, flags, userId);
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7c8515b..4767d3a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1461,8 +1461,9 @@
         private TreeMap<PackageInstallerSession, TreeSet<PackageInstallerSession>> mSessionMap;
 
         private final Comparator<PackageInstallerSession> mSessionCreationComparator =
-                Comparator.comparingLong((PackageInstallerSession sess) -> sess.createdMillis)
-                          .thenComparingInt(sess -> sess.sessionId);
+                Comparator.comparingLong(
+                        (PackageInstallerSession sess) -> sess != null ? sess.createdMillis : -1)
+                        .thenComparingInt(sess -> sess != null ? sess.sessionId : -1);
 
         ParentChildSessionMap() {
             mSessionMap = new TreeMap<>(mSessionCreationComparator);
@@ -1500,10 +1501,12 @@
             for (Map.Entry<PackageInstallerSession, TreeSet<PackageInstallerSession>> entry
                     : mSessionMap.entrySet()) {
                 PackageInstallerSession parentSession = entry.getKey();
-                pw.print(tag + " ");
-                parentSession.dump(pw);
-                pw.println();
-                pw.increaseIndent();
+                if (parentSession != null) {
+                    pw.print(tag + " ");
+                    parentSession.dump(pw);
+                    pw.println();
+                    pw.increaseIndent();
+                }
 
                 for (PackageInstallerSession childSession : entry.getValue()) {
                     pw.print(tag + " Child ");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5526990..9f5adcb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2576,8 +2576,8 @@
         return mComputer.canViewInstantApps(callingUid, userId);
     }
 
-    private PackageInfo generatePackageInfo(@NonNull PackageStateInternal ps, int flags,
-            int userId) {
+    private PackageInfo generatePackageInfo(@NonNull PackageStateInternal ps,
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         return mComputer.generatePackageInfo(ps, flags, userId);
     }
 
@@ -2616,13 +2616,14 @@
     }
 
     @Override
-    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+    public PackageInfo getPackageInfo(String packageName,
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         return mComputer.getPackageInfo(packageName, flags, userId);
     }
 
     @Override
     public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
-            int flags, int userId) {
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         return mComputer.getPackageInfoInternal(versionedPackage.getPackageName(),
                 versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
     }
@@ -2659,7 +2660,7 @@
     }
 
     private boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid,
-            int userId, int flags) {
+            int userId, @PackageManager.ComponentInfoFlags long flags) {
         return mComputer.filterSharedLibPackage(ps, uid, userId, flags);
     }
 
@@ -2674,16 +2675,19 @@
     }
 
     @Override
-    public int getPackageUid(@NonNull String packageName, int flags, @UserIdInt int userId) {
+    public int getPackageUid(@NonNull String packageName,
+        @PackageManager.PackageInfoFlags long flags, @UserIdInt int userId) {
         return mComputer.getPackageUid(packageName, flags, userId);
     }
 
-    private int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) {
+    private int getPackageUidInternal(String packageName,
+            @PackageManager.PackageInfoFlags long flags, int userId, int callingUid) {
         return mComputer.getPackageUidInternal(packageName, flags, userId, callingUid);
     }
 
     @Override
-    public int[] getPackageGids(String packageName, int flags, int userId) {
+    public int[] getPackageGids(String packageName, @PackageManager.PackageInfoFlags long flags,
+            int userId) {
         return mComputer.getPackageGids(packageName, flags, userId);
     }
 
@@ -2696,14 +2700,15 @@
                 .getPermissionGroupInfo(groupName, flags);
     }
 
-    private ApplicationInfo generateApplicationInfoFromSettings(String packageName, int flags,
-            int filterCallingUid, int userId) {
-        return mComputer.generateApplicationInfoFromSettings(packageName, flags,
-                filterCallingUid, userId);
+    private ApplicationInfo generateApplicationInfoFromSettings(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags, int filterCallingUid, int userId) {
+        return mComputer.generateApplicationInfoFromSettings(packageName, flags, filterCallingUid,
+                userId);
     }
 
     @Override
-    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+    public ApplicationInfo getApplicationInfo(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags, int userId) {
         return mComputer.getApplicationInfo(packageName, flags, userId);
     }
 
@@ -2713,7 +2718,8 @@
      * to clearing. Because it can only be provided by trusted code, its value can be
      * trusted and will be used as-is; unlike userId which will be validated by this method.
      */
-    private ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
+    private ApplicationInfo getApplicationInfoInternal(String packageName,
+            @PackageManager.ApplicationInfoFlags long flags,
             int filterCallingUid, int userId) {
         return mComputer.getApplicationInfoInternal(packageName, flags,
                 filterCallingUid, userId);
@@ -2948,21 +2954,21 @@
     /**
      * Update given flags when being used to request {@link PackageInfo}.
      */
-    private int updateFlagsForPackage(int flags, int userId) {
+    private long updateFlagsForPackage(long flags, int userId) {
         return mComputer.updateFlagsForPackage(flags, userId);
     }
 
     /**
      * Update given flags when being used to request {@link ApplicationInfo}.
      */
-    private int updateFlagsForApplication(int flags, int userId) {
+    private long updateFlagsForApplication(long flags, int userId) {
         return mComputer.updateFlagsForApplication(flags, userId);
     }
 
     /**
      * Update given flags when being used to request {@link ComponentInfo}.
      */
-    private int updateFlagsForComponent(int flags, int userId) {
+    private long updateFlagsForComponent(long flags, int userId) {
         return mComputer.updateFlagsForComponent(flags, userId);
     }
 
@@ -2978,7 +2984,7 @@
      * action and a {@code android.intent.category.BROWSABLE} category</li>
      * </ul>
      */
-    int updateFlagsForResolve(int flags, int userId, int callingUid,
+    long updateFlagsForResolve(long flags, int userId, int callingUid,
             boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
         return mComputer.updateFlagsForResolve(flags, userId, callingUid,
                 wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
@@ -2990,7 +2996,8 @@
     }
 
     @Override
-    public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+    public ActivityInfo getActivityInfo(ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, int userId) {
         return mComputer.getActivityInfo(component, flags, userId);
     }
 
@@ -3000,8 +3007,8 @@
      * to clearing. Because it can only be provided by trusted code, its value can be
      * trusted and will be used as-is; unlike userId which will be validated by this method.
      */
-    private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
-            int filterCallingUid, int userId) {
+    private ActivityInfo getActivityInfoInternal(ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, int filterCallingUid, int userId) {
         return mComputer.getActivityInfoInternal(component, flags,
                 filterCallingUid, userId);
     }
@@ -3014,40 +3021,43 @@
     }
 
     @Override
-    public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
+    public ActivityInfo getReceiverInfo(ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, int userId) {
         return mComputer.getReceiverInfo(component, flags, userId);
     }
 
     @Override
     public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
-            int flags, int userId) {
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         return mComputer.getSharedLibraries(packageName, flags, userId);
     }
 
     @Nullable
     @Override
     public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-            @NonNull String packageName, int flags, @UserIdInt int userId) {
+            @NonNull String packageName, @PackageManager.PackageInfoFlags long flags,
+            @NonNull int userId) {
         return mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
     }
 
     @Nullable
     List<VersionedPackage> getPackagesUsingSharedLibrary(
-            SharedLibraryInfo libInfo, int flags, int callingUid, int userId) {
+            SharedLibraryInfo libInfo, @PackageManager.PackageInfoFlags long flags, int callingUid,
+            int userId) {
         return mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
     }
 
     @Nullable
     @Override
-    public ServiceInfo getServiceInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ServiceInfo getServiceInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         return mComputer.getServiceInfo(component, flags, userId);
     }
 
     @Nullable
     @Override
-    public ProviderInfo getProviderInfo(@NonNull ComponentName component, int flags,
-            @UserIdInt int userId) {
+    public ProviderInfo getProviderInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlags long flags, @UserIdInt int userId) {
         return mComputer.getProviderInfo(component, flags, userId);
     }
 
@@ -3336,7 +3346,7 @@
 
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
-            int flags, int userId) {
+            @PackageManager.ResolveInfoFlags long flags, int userId) {
         return mResolveIntentHelper.resolveIntentInternal(intent, resolvedType, flags,
                 0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid());
     }
@@ -3381,7 +3391,7 @@
      */
     @GuardedBy("mLock")
     boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
-            String resolvedType, int flags) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags) {
         return mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
                 resolvedType, flags);
     }
@@ -3389,10 +3399,10 @@
     @GuardedBy("mLock")
     ResolveInfo findPersistentPreferredActivityLP(Intent intent,
             String resolvedType,
-            int flags, List<ResolveInfo> query, boolean debug, int userId) {
+            @PackageManager.ResolveInfoFlags long flags, List<ResolveInfo> query, boolean debug,
+            int userId) {
         return mComputer.findPersistentPreferredActivityLP(intent,
-                resolvedType,
-                flags, query, debug, userId);
+                resolvedType, flags, query, debug, userId);
     }
 
     // findPreferredActivityBody returns two items: a "things changed" flag and a
@@ -3403,7 +3413,7 @@
     }
 
     FindPreferredActivityBodyResult findPreferredActivityInternal(
-            Intent intent, String resolvedType, int flags,
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
             List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
         return mComputer.findPreferredActivityInternal(
@@ -3433,7 +3443,7 @@
 
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
 
@@ -3453,21 +3463,23 @@
     }
 
     @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         return mComputer.queryIntentActivitiesInternal(intent,
                 resolvedType, flags, userId);
     }
 
     @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
-            int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            @PrivateResolveFlags long privateResolveFlags, int filterCallingUid, int userId,
+            boolean resolveForStart, boolean allowDynamicSplits) {
         return mComputer.queryIntentActivitiesInternal(intent,
                 resolvedType, flags, privateResolveFlags,
                 filterCallingUid, userId, resolveForStart, allowDynamicSplits);
     }
 
     private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
-            String resolvedType, int flags, int sourceUserId, int parentUserId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int sourceUserId,
+            int parentUserId) {
         return mComputer.getCrossProfileDomainPreferredLpr(intent,
                 resolvedType, flags, sourceUserId, parentUserId);
     }
@@ -3494,20 +3506,21 @@
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
                 caller, specifics, specificTypes, intent, resolvedType, flags, userId));
     }
 
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(intent,
                 resolvedType, flags, userId, Binder.getCallingUid()));
     }
 
     @Override
-    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
+    public ResolveInfo resolveService(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlags long flags, int userId) {
         final int callingUid = Binder.getCallingUid();
         return mResolveIntentHelper.resolveServiceInternal(intent, resolvedType, flags, userId,
                 callingUid);
@@ -3515,15 +3528,15 @@
 
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         final int callingUid = Binder.getCallingUid();
         return new ParceledListSlice<>(queryIntentServicesInternal(
                 intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
     }
 
     @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
-            String resolvedType, int flags, int userId, int callingUid,
-            boolean includeInstantApps) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId,
+            int callingUid, boolean includeInstantApps) {
         return mComputer.queryIntentServicesInternal(intent,
                 resolvedType, flags, userId, callingUid,
                 includeInstantApps);
@@ -3531,24 +3544,27 @@
 
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
                 intent, resolvedType, flags, userId));
     }
 
     @Override
-    public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+    public ParceledListSlice<PackageInfo> getInstalledPackages(
+            @PackageManager.PackageInfoFlags long flags, int userId) {
         return mComputer.getInstalledPackages(flags, userId);
     }
 
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
-            @NonNull String[] permissions, int flags, @UserIdInt int userId) {
+            @NonNull String[] permissions, @PackageManager.PackageInfoFlags long flags,
+            @UserIdInt int userId) {
         return mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
     }
 
     @Override
-    public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
+    public ParceledListSlice<ApplicationInfo> getInstalledApplications(
+            @PackageManager.ApplicationInfoFlags long flags, int userId) {
         final int callingUid = Binder.getCallingUid();
         return new ParceledListSlice<>(
                 mComputer.getInstalledApplications(flags, userId, callingUid));
@@ -3652,7 +3668,8 @@
     }
 
     @Override
-    public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
+    public ProviderInfo resolveContentProvider(String name,
+            @PackageManager.ResolveInfoFlags long flags, int userId) {
         return mComputer.resolveContentProvider(name, flags, userId, Binder.getCallingUid());
     }
 
@@ -3664,7 +3681,7 @@
     @NonNull
     @Override
     public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable  String processName,
-            int uid, int flags, @Nullable String metaDataKey) {
+            int uid, @PackageManager.ComponentInfoFlags long flags, @Nullable String metaDataKey) {
         return mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
     }
 
@@ -7509,8 +7526,8 @@
 
     private class PackageManagerInternalImpl extends PackageManagerInternal {
         @Override
-        public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
-                int callingUid) {
+        public List<ApplicationInfo> getInstalledApplications(
+                @PackageManager.ApplicationInfoFlags long flags, int userId, int callingUid) {
             return PackageManagerService.this.mComputer.getInstalledApplications(flags, userId,
                     callingUid);
         }
@@ -7705,7 +7722,8 @@
 
         @Override
         public PackageInfo getPackageInfo(
-                String packageName, int flags, int filterCallingUid, int userId) {
+                String packageName, @PackageManager.PackageInfoFlags long flags,
+                int filterCallingUid, int userId) {
             return PackageManagerService.this.mComputer
                     .getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
                             flags, filterCallingUid, userId);
@@ -7833,28 +7851,32 @@
         }
 
         @Override
-        public int getPackageUid(String packageName, int flags, int userId) {
+        public int getPackageUid(String packageName, @PackageManager.PackageInfoFlags long flags,
+                int userId) {
             return PackageManagerService.this
                     .getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
         }
 
         @Override
         public ApplicationInfo getApplicationInfo(
-                String packageName, int flags, int filterCallingUid, int userId) {
+                String packageName, @PackageManager.ApplicationInfoFlags long flags,
+                int filterCallingUid, int userId) {
             return PackageManagerService.this
                     .getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
         }
 
         @Override
         public ActivityInfo getActivityInfo(
-                ComponentName component, int flags, int filterCallingUid, int userId) {
+                ComponentName component, @PackageManager.ComponentInfoFlags long flags,
+                int filterCallingUid, int userId) {
             return PackageManagerService.this
                     .getActivityInfoInternal(component, flags, filterCallingUid, userId);
         }
 
         @Override
         public List<ResolveInfo> queryIntentActivities(
-                Intent intent, String resolvedType, int flags, int filterCallingUid, int userId) {
+                Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+                int filterCallingUid, int userId) {
             return PackageManagerService.this
                     .queryIntentActivitiesInternal(intent, resolvedType, flags, 0, filterCallingUid,
                             userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
@@ -7862,14 +7884,16 @@
 
         @Override
         public List<ResolveInfo> queryIntentReceivers(Intent intent,
-                String resolvedType, int flags, int filterCallingUid, int userId) {
+                String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+                int filterCallingUid, int userId) {
             return PackageManagerService.this.mResolveIntentHelper.queryIntentReceiversInternal(
                     intent, resolvedType, flags, userId, filterCallingUid);
         }
 
         @Override
         public List<ResolveInfo> queryIntentServices(
-                Intent intent, int flags, int callingUid, int userId) {
+                Intent intent, @PackageManager.ResolveInfoFlags long flags, int callingUid,
+                int userId) {
             final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
             return PackageManagerService.this
                     .queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid,
@@ -7935,7 +7959,7 @@
         }
 
         @Override
-        public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) {
+        public boolean isEnabledAndMatches(ParsedMainComponent component, long flags, int userId) {
             return PackageStateUtils.isEnabledAndMatches(
                     getPackageStateInternal(component.getPackageName()), component, flags, userId);
         }
@@ -8137,8 +8161,9 @@
 
         @Override
         public ResolveInfo resolveIntent(Intent intent, String resolvedType,
-                int flags, int privateResolveFlags, int userId, boolean resolveForStart,
-                int filterCallingUid) {
+                @PackageManager.ResolveInfoFlags long flags,
+                @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
+                boolean resolveForStart, int filterCallingUid) {
             return mResolveIntentHelper.resolveIntentInternal(
                     intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
                     filterCallingUid);
@@ -8146,14 +8171,14 @@
 
         @Override
         public ResolveInfo resolveService(Intent intent, String resolvedType,
-                int flags, int userId, int callingUid) {
+                @PackageManager.ResolveInfoFlags long flags, int userId, int callingUid) {
             return mResolveIntentHelper.resolveServiceInternal(intent, resolvedType, flags, userId,
                     callingUid);
         }
 
         @Override
-        public ProviderInfo resolveContentProvider(String name, int flags, int userId,
-                int callingUid) {
+        public ProviderInfo resolveContentProvider(String name,
+                @PackageManager.ResolveInfoFlags long flags, int userId, int callingUid) {
             return PackageManagerService.this.mComputer
                     .resolveContentProvider(name, flags, userId,callingUid);
         }
@@ -9037,9 +9062,12 @@
     @Override
     public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId,
             int userId) {
-        mutateInstalledPackageSetting(packageName, Binder.getCallingUid(), userId, pkgSetting -> {
-            pkgSetting.setSplashScreenTheme(userId, themeId);
-        });
+        final int callingUid = Binder.getCallingUid();
+        enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+                false /* checkShell */, "setSplashScreenTheme");
+        enforceOwnerRights(packageName, callingUid);
+        mutateInstalledPackageSetting(packageName, callingUid, userId,
+                pkgSetting -> pkgSetting.setSplashScreenTheme(userId, themeId));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 1848ef5..3b643b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -1079,7 +1079,7 @@
     public static boolean hasAnyDomainApproval(
             @NonNull DomainVerificationManagerInternal manager,
             @NonNull PackageStateInternal pkgSetting, @NonNull Intent intent,
-            @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
+            @PackageManager.ResolveInfoFlags long resolveInfoFlags, @UserIdInt int userId) {
         return manager.approvalLevelForDomain(pkgSetting, intent, resolveInfoFlags, userId)
                 > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
     }
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index cb97e2a..8c91b16 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -75,8 +75,8 @@
     }
 
     private ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType,
-            int flags, List<ResolveInfo> query, boolean always, boolean removeMatches,
-            boolean debug, int userId) {
+            @PackageManager.ResolveInfoFlags long flags, List<ResolveInfo> query, boolean always,
+            boolean removeMatches, boolean debug, int userId) {
         return findPreferredActivityNotLocked(
                 intent, resolvedType, flags, query, always, removeMatches, debug, userId,
                 UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
@@ -85,8 +85,9 @@
     // TODO: handle preferred activities missing while user has amnesia
     /** <b>must not hold {@link PackageManagerService.mLock}</b> */
     public ResolveInfo findPreferredActivityNotLocked(
-            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
-            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
+            int userId, boolean queryMayBeFiltered) {
         if (Thread.holdsLock(mPm.mLock)) {
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
                     + " is holding mLock", new Throwable());
@@ -675,7 +676,7 @@
         final int callingUid = Binder.getCallingUid();
         intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
         final String resolvedType = intent.resolveTypeIfNeeded(mPm.mContext.getContentResolver());
-        final int flags = mPm.updateFlagsForResolve(
+        final long flags = mPm.updateFlagsForResolve(
                 0, userId, callingUid, false /*includeInstantApps*/,
                 mPm.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
                         0));
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 70855a9..0ee1f89 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -74,8 +74,9 @@
      * However, if {@code resolveForStart} is {@code true}, all instant apps are visible
      * since we need to allow the system to start any installed application.
      */
-    public ResolveInfo resolveIntentInternal(Intent intent, String resolvedType, int flags,
-            @PackageManagerInternal.PrivateResolveFlags int privateResolveFlags, int userId,
+    public ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlags long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
             boolean resolveForStart, int filterCallingUid) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
@@ -114,8 +115,9 @@
     }
 
     private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
-            int flags, int privateResolveFlags, List<ResolveInfo> query, int userId,
-            boolean queryMayBeFiltered) {
+            @PackageManager.ResolveInfoFlags long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
+            List<ResolveInfo> query, int userId, boolean queryMayBeFiltered) {
         if (query != null) {
             final int n = query.size();
             if (n == 1) {
@@ -276,7 +278,8 @@
     // In this method, we have to know the actual calling UID, but in some cases Binder's
     // call identity is removed, so the UID has to be passed in explicitly.
     public @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
-            String resolvedType, int flags, int userId, int filterCallingUid) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId,
+            int filterCallingUid) {
         if (!mPm.mUserManager.exists(userId)) return Collections.emptyList();
         mPm.enforceCrossUserPermission(filterCallingUid, userId, false /*requireFullPermission*/,
                 false /*checkShell*/, "query intent receivers");
@@ -370,8 +373,8 @@
     }
 
 
-    public ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
-            int userId, int callingUid) {
+    public ResolveInfo resolveServiceInternal(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlags long flags, int userId, int callingUid) {
         if (!mPm.mUserManager.exists(userId)) return null;
         flags = mPm.updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
                 false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
@@ -388,7 +391,8 @@
     }
 
     public @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
-            Intent intent, String resolvedType, int flags, int userId) {
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlags long flags,
+            int userId) {
         if (!mPm.mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         final String instantAppPkgName = mPm.getInstantAppPackageName(callingUid);
@@ -529,7 +533,7 @@
 
     public @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
-            String resolvedType, int flags, int userId) {
+            String resolvedType, @PackageManager.ResolveInfoFlags long flags, int userId) {
         if (!mPm.mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         flags = mPm.updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1f5d79c..6a163b2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -154,7 +154,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
@@ -4150,7 +4149,7 @@
         return getDisabledSystemPkgLPr(enabledPackageSetting.getPackageName());
     }
 
-    boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
+    boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, long flags, int userId) {
         final PackageSetting ps = mPackages.get(componentInfo.packageName);
         if (ps == null) return false;
 
@@ -4160,7 +4159,7 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component,
-            int flags, int userId) {
+            long flags, int userId) {
         final PackageSetting ps = mPackages.get(component.getPackageName());
         if (ps == null) return false;
 
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index d54acb7..a5a8d5c 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -24,20 +24,6 @@
       "name": "CtsMatchFlagTestCases"
     },
     {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {
-          "include-filter": "com.android.server.pm."
-        },
-        {
-          "include-annotation": "android.platform.test.annotations.Presubmit"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        }
-      ]
-    },
-    {
       "name": "FrameworksMockingServicesTests",
       "options": [
         {
@@ -46,45 +32,6 @@
       ]
     },
     {
-      "name": "FrameworksServicesTests",
-      "file_patterns": ["(/|^)ShortcutService\\.java"],
-      "options": [
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest1"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest2"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest3"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest4"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest5"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest6"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest7"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest8"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest9"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest10"
-        },
-        {
-          "include-filter": "com.android.server.pm.ShortcutManagerTest11"
-        }
-      ]
-    },
-    {
       "name": "CtsShortcutHostTestCases",
       "file_patterns": ["(/|^)ShortcutService\\.java"]
     },
@@ -188,47 +135,6 @@
     },
     {
       "name": "PackageManagerServiceHostTests"
-    },
-    {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {
-          "install-arg": "-t"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserDataPreparerTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserLifecycleStressTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserManagerServiceCreateProfileTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserManagerServiceIdRecyclingTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserManagerServiceTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserManagerServiceUserInfoTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserManagerServiceUserTypeTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserManagerTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserRestrictionsUtilsTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.UserSystemPackageInstallerTest"
-        },
-        {
-          "include-filter": "com.android.server.pm.parsing.SystemPartitionParseTest"
-        }
-      ]
     }
   ],
   "imports": [
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 74529c5..bc4c8b0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2408,6 +2408,14 @@
         return userTypeDetails != null && canAddMoreUsersOfType(userTypeDetails);
     }
 
+    /** Returns whether the creation of users of the given user type is enabled on this device. */
+    @Override
+    public boolean isUserTypeEnabled(String userType) {
+        checkManageOrCreateUsersPermission("check if user type is enabled.");
+        final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
+        return userTypeDetails != null && userTypeDetails.isEnabled();
+    }
+
     @Override
     public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) {
         return canAddMoreProfilesToUser(UserManager.USER_TYPE_PROFILE_MANAGED, userId,
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 0ab1d36..bcb5e72 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -84,8 +84,8 @@
      */
     @Nullable
     public static PackageInfo generate(AndroidPackage pkg, int[] gids,
-            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
-            Set<String> grantedPermissions, PackageUserState state, int userId,
+            @PackageManager.PackageInfoFlags long flags, long firstInstallTime,
+            long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state, int userId,
             @Nullable PackageStateInternal pkgSetting) {
         return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime,
                 grantedPermissions, state, userId, null, pkgSetting);
@@ -105,8 +105,8 @@
      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
      */
     private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids,
-            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
-            Set<String> grantedPermissions, PackageUserState state, int userId,
+            @PackageManager.PackageInfoFlags long flags, long firstInstallTime,
+            long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state, int userId,
             @Nullable ApexInfo apexInfo, @Nullable PackageStateInternal pkgSetting) {
         ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId,
                 pkgSetting);
@@ -209,7 +209,7 @@
      */
     @Nullable
     public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
-            @PackageManager.ApplicationInfoFlags int flags, @NonNull PackageUserState state,
+            @PackageManager.ApplicationInfoFlags long flags, @NonNull PackageUserState state,
             int userId, @Nullable PackageStateInternal pkgSetting) {
         if (pkg == null) {
             return null;
@@ -255,7 +255,7 @@
      */
     @Nullable
     public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
-            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId,
+            @PackageManager.ComponentInfoFlags long flags, PackageUserState state, int userId,
             @Nullable PackageStateInternal pkgSetting) {
         return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting);
     }
@@ -265,7 +265,7 @@
      */
     @Nullable
     private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
-            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @PackageManager.ComponentInfoFlags long flags, PackageUserState state,
             @Nullable ApplicationInfo applicationInfo, int userId,
             @Nullable PackageStateInternal pkgSetting) {
         if (a == null) return null;
@@ -291,7 +291,7 @@
      */
     @Nullable
     public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
-            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId,
+            @PackageManager.ComponentInfoFlags long flags, PackageUserState state, int userId,
             @Nullable PackageStateInternal pkgSetting) {
         return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting);
     }
@@ -301,7 +301,7 @@
      */
     @Nullable
     private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
-            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @PackageManager.ComponentInfoFlags long flags, PackageUserState state,
             @Nullable ApplicationInfo applicationInfo, int userId,
             @Nullable PackageStateInternal pkgSetting) {
         if (s == null) return null;
@@ -326,7 +326,7 @@
      */
     @Nullable
     public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
-            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @PackageManager.ComponentInfoFlags long flags, PackageUserState state,
             @NonNull ApplicationInfo applicationInfo, int userId,
             @Nullable PackageStateInternal pkgSetting) {
         if (p == null) return null;
@@ -353,7 +353,7 @@
      */
     @Nullable
     public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
-            AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId,
+            AndroidPackage pkg, @PackageManager.ComponentInfoFlags long flags, int userId,
             @Nullable PackageStateInternal pkgSetting) {
         if (i == null) return null;
 
@@ -381,7 +381,7 @@
     //  PackageStateInternal os that checkUseInstalledOrHidden filter can apply
     @Nullable
     public static PermissionInfo generatePermissionInfo(ParsedPermission p,
-            @PackageManager.ComponentInfoFlags int flags) {
+            @PackageManager.ComponentInfoFlags long flags) {
         // TODO(b/135203078): Remove null checks and make all usages @NonNull
         if (p == null) return null;
 
@@ -391,7 +391,7 @@
 
     @Nullable
     public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
-            @PackageManager.ComponentInfoFlags int flags) {
+            @PackageManager.ComponentInfoFlags long flags) {
         if (pg == null) return null;
 
         // For now, permissions don't have state-adjustable fields; return directly
@@ -400,7 +400,7 @@
 
     @Nullable
     public static ArrayMap<String, ProcessInfo> generateProcessInfo(
-            Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags) {
+            Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags long flags) {
         if (procs == null) {
             return null;
         }
@@ -423,7 +423,7 @@
      */
     public static boolean checkUseInstalledOrHidden(AndroidPackage pkg,
             PackageStateInternal pkgSetting, PackageUserState state,
-            @PackageManager.PackageInfoFlags int flags) {
+            @PackageManager.PackageInfoFlags long flags) {
         // Returns false if the package is hidden system app until installed.
         if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
                 && !state.isInstalled()
@@ -628,7 +628,7 @@
          */
         @Nullable
         public ApplicationInfo generate(AndroidPackage pkg,
-                @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId,
+                @PackageManager.ApplicationInfoFlags long flags, PackageUserState state, int userId,
                 @Nullable PackageStateInternal pkgSetting) {
             ApplicationInfo appInfo = mCache.get(pkg.getPackageName());
             if (appInfo != null) {
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 61fd5ee..32b1e5d 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -256,7 +256,7 @@
      * Returns false iff the provided flags include the {@link PackageManager#MATCH_SYSTEM_ONLY}
      * flag and the provided package is not a system package. Otherwise returns {@code true}.
      */
-    public static boolean isMatchForSystemOnly(AndroidPackage pkg, int flags) {
+    public static boolean isMatchForSystemOnly(AndroidPackage pkg, long flags) {
         if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
             return pkg.isSystem();
         }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
index 6744ff5..09b9d31 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
@@ -27,7 +27,7 @@
 
 public class PackageStateUtils {
 
-    public static boolean isMatch(PackageState packageState, int flags) {
+    public static boolean isMatch(PackageState packageState, long flags) {
         if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
             return packageState.isSystem();
         }
@@ -54,7 +54,7 @@
     }
 
     public static boolean isEnabledAndMatches(@Nullable PackageStateInternal packageState,
-            ComponentInfo componentInfo, int flags, int userId) {
+            ComponentInfo componentInfo, long flags, int userId) {
         if (packageState == null) return false;
 
         final PackageUserState userState = packageState.getUserStateOrDefault(userId);
@@ -62,7 +62,7 @@
     }
 
     public static boolean isEnabledAndMatches(@Nullable PackageStateInternal packageState,
-            @NonNull ParsedMainComponent component, int flags, int userId) {
+            @NonNull ParsedMainComponent component, long flags, int userId) {
         if (packageState == null) {
             return false;
         }
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 1f024ea..471f38a 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -391,7 +391,7 @@
      */
     @ApprovalLevel
     int approvalLevelForDomain(@NonNull PackageStateInternal pkgSetting, @NonNull Intent intent,
-            @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId);
+            @PackageManager.ResolveInfoFlags long resolveInfoFlags, @UserIdInt int userId);
 
     /**
      * @return the domain verification set ID for the given package, or null if the ID is
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 0fb8475..661e67d 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -1721,7 +1721,7 @@
 
     @Override
     public int approvalLevelForDomain(@NonNull PackageStateInternal pkgSetting,
-            @NonNull Intent intent, @PackageManager.ResolveInfoFlags int resolveInfoFlags,
+            @NonNull Intent intent, @PackageManager.ResolveInfoFlags long resolveInfoFlags,
             @UserIdInt int userId) {
         String packageName = pkgSetting.getPackageName();
         if (!DomainVerificationUtils.isDomainVerificationIntent(intent, resolveInfoFlags)) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
index 246810f..12cce0d 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
@@ -49,7 +49,7 @@
     }
 
     public static boolean isDomainVerificationIntent(Intent intent,
-            @PackageManager.ResolveInfoFlags int resolveInfoFlags) {
+            @PackageManager.ResolveInfoFlags long resolveInfoFlags) {
         if (!intent.isWebIntent()) {
             return false;
         }
diff --git a/services/core/java/com/android/server/security/AttestationVerificationManagerService.java b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java
new file mode 100644
index 0000000..f519ced
--- /dev/null
+++ b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.security;
+
+import static android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelDuration;
+import android.os.RemoteException;
+import android.security.attestationverification.AttestationProfile;
+import android.security.attestationverification.IAttestationVerificationManagerService;
+import android.security.attestationverification.IVerificationResult;
+import android.security.attestationverification.VerificationToken;
+import android.util.ExceptionUtils;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.server.SystemService;
+
+/**
+ * A {@link SystemService} which provides functionality related to verifying attestations of
+ * (usually) remote computing environments.
+ *
+ * @hide
+ */
+public class AttestationVerificationManagerService extends SystemService {
+
+    private static final String TAG = "AVF";
+
+    public AttestationVerificationManagerService(final Context context) {
+        super(context);
+    }
+
+    private final IBinder mService = new IAttestationVerificationManagerService.Stub() {
+        @Override
+        public void verifyAttestation(
+                AttestationProfile profile,
+                int localBindingType,
+                Bundle requirements,
+                byte[] attestation,
+                AndroidFuture resultCallback) throws RemoteException {
+            try {
+                Slog.d(TAG, "verifyAttestation");
+                verifyAttestationForAllVerifiers(profile, localBindingType, requirements,
+                        attestation, resultCallback);
+            } catch (Throwable t) {
+                Slog.e(TAG, "failed to verify attestation", t);
+                throw ExceptionUtils.propagate(t, RemoteException.class);
+            }
+        }
+
+        @Override
+        public void verifyToken(VerificationToken token, ParcelDuration parcelDuration,
+                AndroidFuture resultCallback) throws RemoteException {
+            // TODO(b/201696614): Implement
+            resultCallback.complete(RESULT_UNKNOWN);
+        }
+    };
+
+    private void verifyAttestationForAllVerifiers(
+            AttestationProfile profile, int localBindingType, Bundle requirements,
+            byte[] attestation, AndroidFuture<IVerificationResult> resultCallback) {
+        // TODO(b/201696614): Implement
+        IVerificationResult result = new IVerificationResult();
+        result.resultCode = RESULT_UNKNOWN;
+        result.token = null;
+        resultCallback.complete(result);
+    }
+
+    @Override
+    public void onStart() {
+        Slog.d(TAG, "Started");
+        publishBinderService(Context.ATTESTATION_VERIFICATION_SERVICE, mService);
+    }
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 3182290..eb69ff7 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -64,6 +64,8 @@
 import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs;
 import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
 
+import static libcore.io.IoUtils.closeQuietly;
+
 import static java.lang.Math.min;
 import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MICROSECONDS;
@@ -222,6 +224,7 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -3413,9 +3416,12 @@
                     metricsState.getGeoDetectionEnabledSetting(),
                     convertToMetricsDetectionMode(metricsState.getDetectionMode()),
                     metricsState.getDeviceTimeZoneIdOrdinal(),
-                    metricsState.getLatestManualSuggestionProtoBytes(),
-                    metricsState.getLatestTelephonySuggestionProtoBytes(),
-                    metricsState.getLatestGeolocationSuggestionProtoBytes()
+                    convertTimeZoneSuggestionToProtoBytes(
+                            metricsState.getLatestManualSuggestion()),
+                    convertTimeZoneSuggestionToProtoBytes(
+                            metricsState.getLatestTelephonySuggestion()),
+                    convertTimeZoneSuggestionToProtoBytes(
+                            metricsState.getLatestGeolocationSuggestion())
             ));
         } catch (RuntimeException e) {
             Slog.e(TAG, "Getting time zone detection state failed: ", e);
@@ -3426,7 +3432,8 @@
         return StatsManager.PULL_SUCCESS;
     }
 
-    private int convertToMetricsDetectionMode(int detectionMode) {
+    private static int convertToMetricsDetectionMode(
+            @MetricsTimeZoneDetectorState.DetectionMode int detectionMode) {
         switch (detectionMode) {
             case MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL:
                 return TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__MANUAL;
@@ -3439,6 +3446,34 @@
         }
     }
 
+    @Nullable
+    private static byte[] convertTimeZoneSuggestionToProtoBytes(
+            @Nullable MetricsTimeZoneDetectorState.MetricsTimeZoneSuggestion suggestion) {
+        if (suggestion == null) {
+            return null;
+        }
+
+        // We don't get access to the atoms.proto definition for nested proto fields, so we use
+        // an identically specified proto.
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        ProtoOutputStream protoOutputStream = new ProtoOutputStream(byteArrayOutputStream);
+        int typeProtoValue = suggestion.isCertain()
+                ? android.app.time.MetricsTimeZoneSuggestion.CERTAIN
+                : android.app.time.MetricsTimeZoneSuggestion.UNCERTAIN;
+        protoOutputStream.write(android.app.time.MetricsTimeZoneSuggestion.TYPE,
+                typeProtoValue);
+        if (suggestion.isCertain()) {
+            for (int zoneIdOrdinal : suggestion.getZoneIdOrdinals()) {
+                protoOutputStream.write(
+                        android.app.time.MetricsTimeZoneSuggestion.TIME_ZONE_ORDINALS,
+                        zoneIdOrdinal);
+            }
+        }
+        protoOutputStream.flush();
+        closeQuietly(byteArrayOutputStream);
+        return byteArrayOutputStream.toByteArray();
+    }
+
     private void registerExternalStorageInfo() {
         int tagId = FrameworkStatsLog.EXTERNAL_STORAGE_INFO;
         mStatsManager.setPullAtomCallback(
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
index 0c20586..f156f8c 100644
--- a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -16,16 +16,12 @@
 
 package com.android.server.timezonedetector;
 
-import static libcore.io.IoUtils.closeQuietly;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.util.proto.ProtoOutputStream;
 
-import java.io.ByteArrayOutputStream;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -50,7 +46,7 @@
             value = { DETECTION_MODE_MANUAL, DETECTION_MODE_GEO, DETECTION_MODE_TELEPHONY})
     @Retention(RetentionPolicy.SOURCE)
     @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
-    @interface DetectionMode {};
+    public @interface DetectionMode {};
 
     public static final @DetectionMode int DETECTION_MODE_MANUAL = 0;
     public static final @DetectionMode int DETECTION_MODE_GEO = 1;
@@ -89,16 +85,16 @@
 
         int deviceTimeZoneIdOrdinal =
                 tzIdOrdinalGenerator.ordinal(Objects.requireNonNull(deviceTimeZoneId));
-        MetricsTimeZoneSuggestion latestObfuscatedManualSuggestion =
+        MetricsTimeZoneSuggestion latestCanonicalManualSuggestion =
                 createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestManualSuggestion);
-        MetricsTimeZoneSuggestion latestObfuscatedTelephonySuggestion =
+        MetricsTimeZoneSuggestion latestCanonicalTelephonySuggestion =
                 createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestTelephonySuggestion);
-        MetricsTimeZoneSuggestion latestObfuscatedGeolocationSuggestion =
+        MetricsTimeZoneSuggestion latestCanonicalGeolocationSuggestion =
                 createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestGeolocationSuggestion);
 
         return new MetricsTimeZoneDetectorState(
-                configurationInternal, deviceTimeZoneIdOrdinal, latestObfuscatedManualSuggestion,
-                latestObfuscatedTelephonySuggestion, latestObfuscatedGeolocationSuggestion);
+                configurationInternal, deviceTimeZoneIdOrdinal, latestCanonicalManualSuggestion,
+                latestCanonicalTelephonySuggestion, latestCanonicalGeolocationSuggestion);
     }
 
     /** Returns true if the device supports telephony time zone detection. */
@@ -154,30 +150,27 @@
     }
 
     /**
-     * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last manual
-     * suggestion received.
+     * Returns a canonical form of the last manual suggestion received.
      */
     @Nullable
-    public byte[] getLatestManualSuggestionProtoBytes() {
-        return suggestionProtoBytes(mLatestManualSuggestion);
+    public MetricsTimeZoneSuggestion getLatestManualSuggestion() {
+        return mLatestManualSuggestion;
     }
 
     /**
-     * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last, best
-     * telephony suggestion received.
+     * Returns a canonical form of the last telephony suggestion received.
      */
     @Nullable
-    public byte[] getLatestTelephonySuggestionProtoBytes() {
-        return suggestionProtoBytes(mLatestTelephonySuggestion);
+    public MetricsTimeZoneSuggestion getLatestTelephonySuggestion() {
+        return mLatestTelephonySuggestion;
     }
 
     /**
-     * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last geolocation
-     * suggestion received.
+     * Returns a canonical form of last geolocation suggestion received.
      */
     @Nullable
-    public byte[] getLatestGeolocationSuggestionProtoBytes() {
-        return suggestionProtoBytes(mLatestGeolocationSuggestion);
+    public MetricsTimeZoneSuggestion getLatestGeolocationSuggestion() {
+        return mLatestGeolocationSuggestion;
     }
 
     @Override
@@ -213,14 +206,6 @@
                 + '}';
     }
 
-    private static byte[] suggestionProtoBytes(
-            @Nullable MetricsTimeZoneSuggestion suggestion) {
-        if (suggestion == null) {
-            return null;
-        }
-        return suggestion.toBytes();
-    }
-
     @Nullable
     private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
             @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
@@ -264,10 +249,11 @@
     }
 
     /**
-     * A Java class that closely matches the android.app.time.MetricsTimeZoneSuggestion
-     * proto definition.
+     * A Java class that represents a generic time zone suggestion, i.e. one that is independent of
+     * origin-specific information. This closely matches the metrics atoms.proto
+     * MetricsTimeZoneSuggestion proto definition.
      */
-    private static final class MetricsTimeZoneSuggestion {
+    public static final class MetricsTimeZoneSuggestion {
         @Nullable
         private final int[] mZoneIdOrdinals;
 
@@ -281,42 +267,20 @@
         }
 
         @NonNull
-        public static MetricsTimeZoneSuggestion createCertain(
+        static MetricsTimeZoneSuggestion createCertain(
                 @NonNull int[] zoneIdOrdinals) {
             return new MetricsTimeZoneSuggestion(zoneIdOrdinals);
         }
 
-        boolean isCertain() {
+        public boolean isCertain() {
             return mZoneIdOrdinals != null;
         }
 
         @Nullable
-        int[] getZoneIdOrdinals() {
+        public int[] getZoneIdOrdinals() {
             return mZoneIdOrdinals;
         }
 
-        byte[] toBytes() {
-            // We don't get access to the atoms.proto definition for nested proto fields, so we use
-            // an identically specified proto.
-            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-            ProtoOutputStream protoOutputStream = new ProtoOutputStream(byteArrayOutputStream);
-            int typeProtoValue = isCertain()
-                    ? android.app.time.MetricsTimeZoneSuggestion.CERTAIN
-                    : android.app.time.MetricsTimeZoneSuggestion.UNCERTAIN;
-            protoOutputStream.write(android.app.time.MetricsTimeZoneSuggestion.TYPE,
-                    typeProtoValue);
-            if (isCertain()) {
-                for (int zoneIdOrdinal : getZoneIdOrdinals()) {
-                    protoOutputStream.write(
-                            android.app.time.MetricsTimeZoneSuggestion.TIME_ZONE_ORDINALS,
-                            zoneIdOrdinal);
-                }
-            }
-            protoOutputStream.flush();
-            closeQuietly(byteArrayOutputStream);
-            return byteArrayOutputStream.toByteArray();
-        }
-
         @Override
         public boolean equals(Object o) {
             if (this == o) {
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 984b9ba..692b0cc 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -172,12 +172,13 @@
      * Enables/disables the state recording mode for tests. The value is reset with {@link
      * #resetVolatileTestConfig()}.
      */
-    void setRecordProviderStateChanges(boolean enabled);
+    void setRecordStateChangesForTests(boolean enabled);
 
     /**
-     * Returns {@code true} if providers are expected to record their state changes for tests.
+     * Returns {@code true} if the controller / providers are expected to record their state changes
+     * for tests.
      */
-    boolean getRecordProviderStateChanges();
+    boolean getRecordStateChangesForTests();
 
     /**
      * Returns the mode for the primary location time zone provider.
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
index b9885d2..02ea433 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
@@ -150,7 +150,7 @@
      * See also {@link #resetVolatileTestConfig()}.
      */
     @GuardedBy("this")
-    private boolean mRecordProviderStateChanges;
+    private boolean mRecordStateChangesForTests;
 
     private ServiceConfigAccessorImpl(@NonNull Context context) {
         mContext = Objects.requireNonNull(context);
@@ -453,13 +453,13 @@
     }
 
     @Override
-    public synchronized void setRecordProviderStateChanges(boolean enabled) {
-        mRecordProviderStateChanges = enabled;
+    public synchronized void setRecordStateChangesForTests(boolean enabled) {
+        mRecordStateChangesForTests = enabled;
     }
 
     @Override
-    public synchronized boolean getRecordProviderStateChanges() {
-        return mRecordProviderStateChanges;
+    public synchronized boolean getRecordStateChangesForTests() {
+        return mRecordStateChangesForTests;
     }
 
     @Override
@@ -548,7 +548,7 @@
         mTestPrimaryLocationTimeZoneProviderMode = null;
         mTestSecondaryLocationTimeZoneProviderPackageName = null;
         mTestSecondaryLocationTimeZoneProviderMode = null;
-        mRecordProviderStateChanges = false;
+        mRecordStateChangesForTests = false;
     }
 
     private boolean isTelephonyFallbackSupported() {
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index af8cf6e..b23f11a 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -247,8 +247,7 @@
      * completion, it cannot be called from the {@code mThreadingDomain} thread.
      */
     void startWithTestProviders(@Nullable String testPrimaryProviderPackageName,
-            @Nullable String testSecondaryProviderPackageName,
-            boolean recordProviderStateChanges) {
+            @Nullable String testSecondaryProviderPackageName, boolean recordStateChanges) {
         enforceManageTimeZoneDetectorPermission();
 
         if (testPrimaryProviderPackageName == null && testSecondaryProviderPackageName == null) {
@@ -263,7 +262,7 @@
                         testPrimaryProviderPackageName);
                 mServiceConfigAccessor.setTestSecondaryLocationTimeZoneProviderPackageName(
                         testSecondaryProviderPackageName);
-                mServiceConfigAccessor.setRecordProviderStateChanges(recordProviderStateChanges);
+                mServiceConfigAccessor.setRecordStateChangesForTests(recordStateChanges);
                 startOnDomainThread();
             }
         }, BLOCKING_OP_WAIT_DURATION_MILLIS);
@@ -281,10 +280,20 @@
             if (mLocationTimeZoneProviderController == null) {
                 LocationTimeZoneProvider primary = mPrimaryProviderConfig.createProvider();
                 LocationTimeZoneProvider secondary = mSecondaryProviderConfig.createProvider();
+                LocationTimeZoneProviderController.MetricsLogger metricsLogger =
+                        new LocationTimeZoneProviderController.MetricsLogger() {
+                            @Override
+                            public void onStateChange(
+                                    @LocationTimeZoneProviderController.State String state) {
+                                // TODO b/200279201 - wire this up to metrics code
+                                // No-op.
+                            }
+                        };
 
+                boolean recordStateChanges = mServiceConfigAccessor.getRecordStateChangesForTests();
                 LocationTimeZoneProviderController controller =
-                        new LocationTimeZoneProviderController(
-                                mThreadingDomain, primary, secondary);
+                        new LocationTimeZoneProviderController(mThreadingDomain, metricsLogger,
+                                primary, secondary, recordStateChanges);
                 LocationTimeZoneProviderControllerEnvironmentImpl environment =
                         new LocationTimeZoneProviderControllerEnvironmentImpl(
                                 mThreadingDomain, mServiceConfigAccessor, controller);
@@ -342,7 +351,7 @@
         mThreadingDomain.postAndWait(() -> {
             synchronized (mSharedLock) {
                 if (mLocationTimeZoneProviderController != null) {
-                    mLocationTimeZoneProviderController.clearRecordedProviderStates();
+                    mLocationTimeZoneProviderController.clearRecordedStates();
                 }
             }
         }, BLOCKING_OP_WAIT_DURATION_MILLIS);
@@ -450,7 +459,7 @@
             ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(mIndex);
             return new BinderLocationTimeZoneProvider(
                     providerMetricsLogger, mThreadingDomain, mName, proxy,
-                    mServiceConfigAccessor.getRecordProviderStateChanges());
+                    mServiceConfigAccessor.getRecordStateChangesForTests());
         }
 
         @Override
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerServiceState.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerServiceState.java
index 113926a..1f752f4 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerServiceState.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerServiceState.java
@@ -21,6 +21,7 @@
 
 import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
 import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState;
+import com.android.server.timezonedetector.location.LocationTimeZoneProviderController.State;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -30,22 +31,35 @@
 /** A snapshot of the location time zone manager service's state for tests. */
 final class LocationTimeZoneManagerServiceState {
 
+    private final @State String mControllerState;
     @Nullable private final GeolocationTimeZoneSuggestion mLastSuggestion;
+    @NonNull private final List<@State String> mControllerStates;
     @NonNull private final List<ProviderState> mPrimaryProviderStates;
     @NonNull private final List<ProviderState> mSecondaryProviderStates;
 
     LocationTimeZoneManagerServiceState(@NonNull Builder builder) {
+        mControllerState = builder.mControllerState;
         mLastSuggestion = builder.mLastSuggestion;
+        mControllerStates = Objects.requireNonNull(builder.mControllerStates);
         mPrimaryProviderStates = Objects.requireNonNull(builder.mPrimaryProviderStates);
         mSecondaryProviderStates = Objects.requireNonNull(builder.mSecondaryProviderStates);
     }
 
+    public @State String getControllerState() {
+        return mControllerState;
+    }
+
     @Nullable
     public GeolocationTimeZoneSuggestion getLastSuggestion() {
         return mLastSuggestion;
     }
 
     @NonNull
+    public List<@State String> getControllerStates() {
+        return mControllerStates;
+    }
+
+    @NonNull
     public List<ProviderState> getPrimaryProviderStates() {
         return Collections.unmodifiableList(mPrimaryProviderStates);
     }
@@ -58,7 +72,9 @@
     @Override
     public String toString() {
         return "LocationTimeZoneManagerServiceState{"
-                + "mLastSuggestion=" + mLastSuggestion
+                + "mControllerState=" + mControllerState
+                + ", mLastSuggestion=" + mLastSuggestion
+                + ", mControllerStates=" + mControllerStates
                 + ", mPrimaryProviderStates=" + mPrimaryProviderStates
                 + ", mSecondaryProviderStates=" + mSecondaryProviderStates
                 + '}';
@@ -66,17 +82,31 @@
 
     static final class Builder {
 
+        private @State String mControllerState;
         private GeolocationTimeZoneSuggestion mLastSuggestion;
+        private List<@State String> mControllerStates;
         private List<ProviderState> mPrimaryProviderStates;
         private List<ProviderState> mSecondaryProviderStates;
 
         @NonNull
+        public Builder setControllerState(@State String stateEnum) {
+            mControllerState = stateEnum;
+            return this;
+        }
+
+        @NonNull
         Builder setLastSuggestion(@NonNull GeolocationTimeZoneSuggestion lastSuggestion) {
             mLastSuggestion = Objects.requireNonNull(lastSuggestion);
             return this;
         }
 
         @NonNull
+        public Builder setStateChanges(@NonNull List<@State String> states) {
+            mControllerStates = new ArrayList<>(states);
+            return this;
+        }
+
+        @NonNull
         Builder setPrimaryProviderStateChanges(@NonNull List<ProviderState> primaryProviderStates) {
             mPrimaryProviderStates = new ArrayList<>(primaryProviderStates);
             return this;
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
index 6c9e174..60bbea7 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
@@ -40,6 +40,14 @@
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_UNKNOWN;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_CERTAIN;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_DESTROYED;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_FAILED;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_INITIALIZING;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_PROVIDERS_INITIALIZING;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_STOPPED;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_UNCERTAIN;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_UNKNOWN;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -55,6 +63,7 @@
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
 import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
+import com.android.server.timezonedetector.location.LocationTimeZoneProviderController.State;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -245,6 +254,7 @@
             outputStream.end(lastSuggestionToken);
         }
 
+        writeControllerStates(outputStream, state.getControllerStates());
         writeProviderStates(outputStream, state.getPrimaryProviderStates(),
                 "primary_provider_states",
                 LocationTimeZoneManagerServiceStateProto.PRIMARY_PROVIDER_STATES);
@@ -256,6 +266,37 @@
         return 0;
     }
 
+    private static void writeControllerStates(DualDumpOutputStream outputStream,
+            List<@State String> states) {
+        for (@State String state : states) {
+            outputStream.write("controller_states",
+                    LocationTimeZoneManagerServiceStateProto.CONTROLLER_STATES,
+                    convertControllerStateToProtoEnum(state));
+        }
+    }
+
+    private static int convertControllerStateToProtoEnum(@State String state) {
+        switch (state) {
+            case STATE_PROVIDERS_INITIALIZING:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_PROVIDERS_INITIALIZING;
+            case STATE_STOPPED:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_STOPPED;
+            case STATE_INITIALIZING:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_INITIALIZING;
+            case STATE_UNCERTAIN:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_UNCERTAIN;
+            case STATE_CERTAIN:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_CERTAIN;
+            case STATE_FAILED:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_FAILED;
+            case STATE_DESTROYED:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_DESTROYED;
+            case STATE_UNKNOWN:
+            default:
+                return LocationTimeZoneManagerProto.CONTROLLER_STATE_UNKNOWN;
+        }
+    }
+
     private static void writeProviderStates(DualDumpOutputStream outputStream,
             List<LocationTimeZoneProvider.ProviderState> providerStates, String fieldName,
             long fieldId) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java
index dbd3877..5d7730a 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java
@@ -34,6 +34,7 @@
 import android.annotation.ElapsedRealtimeLong;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringDef;
 import android.service.timezone.TimeZoneProviderEvent;
 import android.service.timezone.TimeZoneProviderSuggestion;
 import android.util.IndentingPrintWriter;
@@ -43,9 +44,15 @@
 import com.android.server.timezonedetector.ConfigurationInternal;
 import com.android.server.timezonedetector.Dumpable;
 import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
+import com.android.server.timezonedetector.ReferenceWithHistory;
 import com.android.server.timezonedetector.location.ThreadingDomain.SingleRunnableQueue;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Objects;
 
 /**
@@ -93,6 +100,36 @@
  */
 class LocationTimeZoneProviderController implements Dumpable {
 
+    // String is used for easier logging / interpretation in bug reports Vs int.
+    @StringDef(prefix = "STATE_",
+            value = { STATE_UNKNOWN, STATE_PROVIDERS_INITIALIZING, STATE_STOPPED,
+                    STATE_INITIALIZING, STATE_UNCERTAIN, STATE_CERTAIN, STATE_FAILED,
+                    STATE_DESTROYED })
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
+    @interface State {}
+
+    /** The state used for an uninitialized controller. */
+    static final @State String STATE_UNKNOWN = "UNKNOWN";
+
+    /**
+     * A state used while the location time zone providers are initializing. Enables detection
+     * / avoidance of unwanted fail-over behavior before both providers are initialized.
+     */
+    static final @State String STATE_PROVIDERS_INITIALIZING = "PROVIDERS_INITIALIZING";
+    /** An inactive state: Detection is disabled. */
+    static final @State String STATE_STOPPED = "STOPPED";
+    /** An active state: No suggestion has yet been made. */
+    static final @State String STATE_INITIALIZING = "INITIALIZING";
+    /** An active state: The last suggestion was "uncertain". */
+    static final @State String STATE_UNCERTAIN = "UNCERTAIN";
+    /** An active state: The last suggestion was "certain". */
+    static final @State String STATE_CERTAIN = "CERTAIN";
+    /** An inactive state: The location time zone providers have failed. */
+    static final @State String STATE_FAILED = "FAILED";
+    /** An inactive state: The controller is destroyed. */
+    static final @State String STATE_DESTROYED = "DESTROYED";
+
     @NonNull private final ThreadingDomain mThreadingDomain;
     @NonNull private final Object mSharedLock;
     /**
@@ -102,6 +139,7 @@
      */
     @NonNull private final SingleRunnableQueue mUncertaintyTimeoutQueue;
 
+    @NonNull private final MetricsLogger mMetricsLogger;
     @NonNull private final LocationTimeZoneProvider mPrimaryProvider;
     @NonNull private final LocationTimeZoneProvider mSecondaryProvider;
 
@@ -117,10 +155,22 @@
     // Non-null after initialize()
     private Callback mCallback;
 
-    /** Indicates both providers have completed initialization. */
-    @GuardedBy("mSharedLock")
-    private boolean mProvidersInitialized;
+    /** Usually {@code false} but can be set to {@code true} to record state changes for testing. */
+    private final boolean mRecordStateChanges;
 
+    @GuardedBy("mSharedLock")
+    @NonNull
+    private final ArrayList<@State String> mRecordedStates = new ArrayList<>(0);
+
+    /**
+     * The current state. This is primarily for metrics / reporting of how long the controller
+     * spends active / inactive during a period. There is overlap with the provider states, but
+     * providers operate independently of each other, so this can help to understand how long the
+     * geo detection system overall was certain or uncertain when multiple providers might have been
+     * enabled concurrently.
+     */
+    @GuardedBy("mSharedLock")
+    private final ReferenceWithHistory<@State String> mState = new ReferenceWithHistory<>(10);
 
     /** Contains the last suggestion actually made, if there is one. */
     @GuardedBy("mSharedLock")
@@ -128,13 +178,21 @@
     private GeolocationTimeZoneSuggestion mLastSuggestion;
 
     LocationTimeZoneProviderController(@NonNull ThreadingDomain threadingDomain,
+            @NonNull MetricsLogger metricsLogger,
             @NonNull LocationTimeZoneProvider primaryProvider,
-            @NonNull LocationTimeZoneProvider secondaryProvider) {
+            @NonNull LocationTimeZoneProvider secondaryProvider,
+            boolean recordStateChanges) {
         mThreadingDomain = Objects.requireNonNull(threadingDomain);
         mSharedLock = threadingDomain.getLockObject();
         mUncertaintyTimeoutQueue = threadingDomain.createSingleRunnableQueue();
+        mMetricsLogger = Objects.requireNonNull(metricsLogger);
         mPrimaryProvider = Objects.requireNonNull(primaryProvider);
         mSecondaryProvider = Objects.requireNonNull(secondaryProvider);
+        mRecordStateChanges = recordStateChanges;
+
+        synchronized (mSharedLock) {
+            mState.set(STATE_UNKNOWN);
+        }
     }
 
     /**
@@ -152,9 +210,10 @@
 
             LocationTimeZoneProvider.ProviderListener providerListener =
                     LocationTimeZoneProviderController.this::onProviderStateChange;
+            setState(STATE_PROVIDERS_INITIALIZING);
             mPrimaryProvider.initialize(providerListener);
             mSecondaryProvider.initialize(providerListener);
-            mProvidersInitialized = true;
+            setState(STATE_STOPPED);
 
             alterProvidersStartedStateIfRequired(
                     null /* oldConfiguration */, mCurrentUserConfiguration);
@@ -209,8 +268,26 @@
 
         synchronized (mSharedLock) {
             stopProviders();
+
+            // Enter destroyed state.
             mPrimaryProvider.destroy();
             mSecondaryProvider.destroy();
+            setState(STATE_DESTROYED);
+        }
+    }
+
+    /**
+     * Updates {@link #mState} if needed, and performs all the record-keeping / callbacks associated
+     * with state changes.
+     */
+    @GuardedBy("mSharedLock")
+    private void setState(@State String state) {
+        if (!Objects.equals(mState.get(), state)) {
+            mState.set(state);
+            if (mRecordStateChanges) {
+                mRecordedStates.add(state);
+            }
+            mMetricsLogger.onStateChange(state);
         }
     }
 
@@ -226,11 +303,12 @@
         // suggestion must now be made to indicate the controller {does not / no longer has}
         // an opinion and will not be sending further updates (until at least the providers are
         // re-started).
-        if (mLastSuggestion != null && mLastSuggestion.getZoneIds() != null) {
+        if (Objects.equals(mState.get(), STATE_CERTAIN)) {
             GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
                     mEnvironment.elapsedRealtimeMillis(), "Providers are stopping");
-            makeSuggestion(suggestion);
+            makeSuggestion(suggestion, STATE_UNCERTAIN);
         }
+        setState(STATE_STOPPED);
     }
 
     @GuardedBy("mSharedLock")
@@ -300,6 +378,8 @@
         //    timeout started when the primary entered {started uncertain} should be cancelled.
 
         if (newGeoDetectionEnabled) {
+            setState(STATE_INITIALIZING);
+
             // Try to start the primary provider.
             tryStartProvider(mPrimaryProvider, newConfiguration);
 
@@ -314,13 +394,13 @@
                 ProviderState newSecondaryState = mSecondaryProvider.getCurrentState();
                 if (!newSecondaryState.isStarted()) {
                     // If both providers are {perm failed} then the controller immediately
-                    // becomes uncertain.
+                    // reports uncertain.
                     GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
                             mEnvironment.elapsedRealtimeMillis(),
                             "Providers are failed:"
                                     + " primary=" + mPrimaryProvider.getCurrentState()
                                     + " secondary=" + mPrimaryProvider.getCurrentState());
-                    makeSuggestion(suggestion);
+                    makeSuggestion(suggestion, STATE_FAILED);
                 }
             }
         } else {
@@ -368,7 +448,7 @@
             // Ignore provider state changes during initialization. e.g. if the primary provider
             // moves to PROVIDER_STATE_PERM_FAILED during initialization, the secondary will not
             // be ready to take over yet.
-            if (!mProvidersInitialized) {
+            if (Objects.equals(mState.get(), STATE_PROVIDERS_INITIALIZING)) {
                 warnLog("onProviderStateChange: Ignoring provider state change because both"
                         + " providers have not yet completed initialization."
                         + " providerState=" + providerState);
@@ -453,13 +533,13 @@
             cancelUncertaintyTimeout();
 
             // If both providers are now terminated, then a suggestion must be sent informing the
-            // time zone detector that there are no further updates coming in future.
+            // time zone detector that there are no further updates coming in the future.
             GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
                     mEnvironment.elapsedRealtimeMillis(),
                     "Both providers are terminated:"
                             + " primary=" + primaryCurrentState.provider
                             + ", secondary=" + secondaryCurrentState.provider);
-            makeSuggestion(suggestion);
+            makeSuggestion(suggestion, STATE_FAILED);
         }
     }
 
@@ -548,7 +628,7 @@
                 + ", providerEvent=" + providerEvent
                 + ", suggestionCreationTime=" + mEnvironment.elapsedRealtimeMillis();
         geoSuggestion.addDebugInfo(debugInfo);
-        makeSuggestion(geoSuggestion);
+        makeSuggestion(geoSuggestion, STATE_CERTAIN);
     }
 
     @Override
@@ -563,8 +643,14 @@
             ipw.println("providerInitializationTimeoutFuzz="
                     + mEnvironment.getProviderInitializationTimeoutFuzz());
             ipw.println("uncertaintyDelay=" + mEnvironment.getUncertaintyDelay());
+            ipw.println("mState=" + mState.get());
             ipw.println("mLastSuggestion=" + mLastSuggestion);
 
+            ipw.println("State history:");
+            ipw.increaseIndent(); // level 2
+            mState.dump(ipw);
+            ipw.decreaseIndent(); // level 2
+
             ipw.println("Primary Provider:");
             ipw.increaseIndent(); // level 2
             mPrimaryProvider.dump(ipw, args);
@@ -579,12 +665,17 @@
         }
     }
 
-    /** Sends an immediate suggestion, updating mLastSuggestion. */
+    /**
+     * Sends an immediate suggestion and enters a new state if needed. This method updates
+     * mLastSuggestion and changes mStateEnum / reports the new state for metrics.
+     */
     @GuardedBy("mSharedLock")
-    private void makeSuggestion(@NonNull GeolocationTimeZoneSuggestion suggestion) {
+    private void makeSuggestion(@NonNull GeolocationTimeZoneSuggestion suggestion,
+            @State String newState) {
         debugLog("makeSuggestion: suggestion=" + suggestion);
         mCallback.suggest(suggestion);
         mLastSuggestion = suggestion;
+        setState(newState);
     }
 
     /** Clears the uncertainty timeout. */
@@ -604,7 +695,7 @@
      * <p>This method schedules an "uncertainty" timeout (if one isn't already scheduled) to be
      * triggered later if nothing else preempts it. It can be preempted if the provider becomes
      * certain (or does anything else that calls {@link
-     * #makeSuggestion(GeolocationTimeZoneSuggestion)}) within {@link
+     * #makeSuggestion(GeolocationTimeZoneSuggestion, String)}) within {@link
      * Environment#getUncertaintyDelay()}. Preemption causes the scheduled
      * "uncertainty" timeout to be cancelled. If the provider repeatedly sends uncertainty events
      * within the uncertainty delay period, those events are effectively ignored (i.e. the timeout
@@ -666,7 +757,7 @@
                             + Duration.ofMillis(afterUncertaintyTimeoutElapsedMillis)
                             + ", uncertaintyDelay=" + uncertaintyDelay
             );
-            makeSuggestion(suggestion);
+            makeSuggestion(suggestion, STATE_UNCERTAIN);
         }
     }
 
@@ -682,12 +773,13 @@
     }
 
     /**
-     * Clears recorded provider state changes (for use during tests).
+     * Clears recorded controller and provider state changes (for use during tests).
      */
-    void clearRecordedProviderStates() {
+    void clearRecordedStates() {
         mThreadingDomain.assertCurrentThread();
 
         synchronized (mSharedLock) {
+            mRecordedStates.clear();
             mPrimaryProvider.clearRecordedStates();
             mSecondaryProvider.clearRecordedStates();
         }
@@ -706,7 +798,9 @@
             if (mLastSuggestion != null) {
                 builder.setLastSuggestion(mLastSuggestion);
             }
-            builder.setPrimaryProviderStateChanges(mPrimaryProvider.getRecordedStates())
+            builder.setControllerState(mState.get())
+                    .setStateChanges(mRecordedStates)
+                    .setPrimaryProviderStateChanges(mPrimaryProvider.getRecordedStates())
                     .setSecondaryProviderStateChanges(mSecondaryProvider.getRecordedStates());
             return builder.build();
         }
@@ -782,4 +876,12 @@
          */
         abstract void suggest(@NonNull GeolocationTimeZoneSuggestion suggestion);
     }
+
+    /**
+     * Used by {@link LocationTimeZoneProviderController} to record events for metrics / telemetry.
+     */
+    interface MetricsLogger {
+        /** Called when the controller's state changes. */
+        void onStateChange(@State String stateEnum);
+    }
 }
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 5d40c23..9717201 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -341,7 +341,7 @@
             if (!isEffectValid(effect)) {
                 return false;
             }
-            attrs = fixupVibrationAttributes(attrs);
+            attrs = fixupVibrationAttributes(attrs, effect);
             synchronized (mLock) {
                 SparseArray<PrebakedSegment> effects = fixupAlwaysOnEffectsLocked(effect);
                 if (effects == null) {
@@ -385,7 +385,7 @@
             if (!isEffectValid(effect)) {
                 return null;
             }
-            attrs = fixupVibrationAttributes(attrs);
+            attrs = fixupVibrationAttributes(attrs, effect);
             Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
                     uid, opPkg, reason);
             fillVibrationFallbacks(vib, effect);
@@ -895,21 +895,32 @@
      * Return new {@link VibrationAttributes} that only applies flags that this user has permissions
      * to use.
      */
-    private VibrationAttributes fixupVibrationAttributes(@Nullable VibrationAttributes attrs) {
+    @NonNull
+    private VibrationAttributes fixupVibrationAttributes(@Nullable VibrationAttributes attrs,
+            CombinedVibration effect) {
         if (attrs == null) {
             attrs = DEFAULT_ATTRIBUTES;
         }
+        int usage = attrs.getUsage();
+        if ((usage == VibrationAttributes.USAGE_UNKNOWN) && effect.isHapticFeedbackCandidate()) {
+            usage = VibrationAttributes.USAGE_TOUCH;
+        }
+        int flags = attrs.getFlags();
         if (attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) {
             if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
                     || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                     || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
-                final int flags = attrs.getFlags()
-                        & ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
-                attrs = new VibrationAttributes.Builder(attrs)
-                        .setFlags(flags, attrs.getFlags()).build();
+                // Remove bypass policy flag from attributes if the app does not have permissions.
+                flags &= ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
             }
         }
-        return attrs;
+        if ((usage == attrs.getUsage()) && (flags == attrs.getFlags())) {
+            return attrs;
+        }
+        return new VibrationAttributes.Builder(attrs)
+                .setUsage(usage)
+                .setFlags(flags, attrs.getFlags())
+                .build();
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 73a783e..bb7434d 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2784,8 +2784,8 @@
         // If it exist, we need to reparent target root task from TDA to launch root task.
         final TaskDisplayArea tda = mTargetRootTask.getDisplayArea();
         final Task launchRootTask = tda.getLaunchRootTask(mTargetRootTask.getWindowingMode(),
-                mTargetRootTask.getActivityType(), null /** options */,
-                mSourceRootTask, 0 /** launchFlags */);
+                mTargetRootTask.getActivityType(), null /** options */, mSourceRootTask,
+                mLaunchFlags);
         // If target root task is created by organizer, let organizer handle reparent itself.
         if (!mTargetRootTask.mCreatedByOrganizer && launchRootTask != null
                 && launchRootTask != mTargetRootTask) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3ede408..a72cf3a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -176,6 +176,7 @@
 import com.android.server.restrictions.RestrictionsManagerService;
 import com.android.server.role.RoleServicePlatformHelper;
 import com.android.server.rotationresolver.RotationResolverManagerService;
+import com.android.server.security.AttestationVerificationManagerService;
 import com.android.server.security.FileIntegrityService;
 import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.security.KeyChainSystemService;
@@ -2339,6 +2340,10 @@
                 t.traceEnd();
             }
 
+            t.traceBegin("StartAttestationVerificationService");
+            mSystemServiceManager.startService(AttestationVerificationManagerService.class);
+            t.traceEnd();
+
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP)) {
                 t.traceBegin("StartCompanionDeviceManager");
                 mSystemServiceManager.startService(COMPANION_DEVICE_MANAGER_SERVICE_CLASS);
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index adf892a..5dc048b 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -28,6 +28,7 @@
 
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
@@ -150,7 +151,7 @@
             PackageInfo packageInfo, @UserIdInt int userId, int uid) {
         when(mPackageManagerInternal.getPackageInfo(
                         eq(CROSS_PROFILE_APP_PACKAGE_NAME),
-                        /* flags= */ anyInt(),
+                        /* flags= */ anyLong(),
                         /* filterCallingUid= */ anyInt(),
                         eq(userId)))
                 .thenReturn(packageInfo);
@@ -469,7 +470,7 @@
     private void mockUninstallCrossProfileAppFromWorkProfile() {
         when(mPackageManagerInternal.getPackageInfo(
                         eq(CROSS_PROFILE_APP_PACKAGE_NAME),
-                        /* flags= */ anyInt(),
+                        /* flags= */ anyLong(),
                         /* filterCallingUid= */ anyInt(),
                         eq(WORK_PROFILE_USER_ID)))
                 .thenReturn(null);
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt
index 98634b2..ac6b679 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt
@@ -120,7 +120,7 @@
     @Test
     fun verify() {
         val flags = if (params.matchDefaultOnly) PackageManager.MATCH_DEFAULT_ONLY else 0
-        assertThat(DomainVerificationUtils.isDomainVerificationIntent(params.intent, flags))
-            .isEqualTo(params.expected)
+        assertThat(DomainVerificationUtils.isDomainVerificationIntent(params.intent,
+            flags.toLong())).isEqualTo(params.expected)
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index a9099ae..5885470 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -2961,7 +2961,7 @@
     private void registerAppIds(String[] packages, Integer[] ids) {
         assertEquals(packages.length, ids.length);
 
-        when(mPackageManagerInternal.getPackageUid(anyString(), anyInt(), anyInt())).thenAnswer(
+        when(mPackageManagerInternal.getPackageUid(anyString(), anyLong(), anyInt())).thenAnswer(
                 invocation -> {
                     final String pkg = invocation.getArgument(0);
                     final int index = ArrayUtils.indexOf(packages, pkg);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
index b2847ce..783971a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
@@ -22,6 +22,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -80,7 +81,7 @@
         doReturn(mActivityManagerInternal).when(
                 () -> LocalServices.getService(ActivityManagerInternal.class));
         doReturn(mIPackageManager).when(() -> AppGlobals.getPackageManager());
-        when(mIPackageManager.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt(), anyInt())).thenReturn(
+        when(mIPackageManager.getPackageUid(eq(TEST_PACKAGE_NAME), anyLong(), anyInt())).thenReturn(
                 TEST_CALLING_UID);
         ActivityManagerConstants constants = mock(ActivityManagerConstants.class);
         constants.PENDINGINTENT_WARNING_THRESHOLD = 2000;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/LocationAttributionHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/LocationAttributionHelperTest.java
index e2e7f5d..94dcdf9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/LocationAttributionHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/LocationAttributionHelperTest.java
@@ -58,72 +58,86 @@
     @Test
     public void testLocationMonitoring() {
         CallerIdentity caller1 = CallerIdentity.forTest(1, 1, "test1", null);
-        Object key1 = new Object();
-        Object key2 = new Object();
         CallerIdentity caller2 = CallerIdentity.forTest(2, 2, "test2", null);
-        Object key3 = new Object();
-        Object key4 = new Object();
 
-        mHelper.reportLocationStart(caller1, "gps", key1);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION, caller1);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION, caller1);
+        mHelper.reportLocationStart(caller1);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller1));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller1));
 
-        mHelper.reportLocationStart(caller1, "gps", key2);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION, caller1);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION, caller1);
+        mHelper.reportLocationStart(caller1);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller1));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller1));
 
-        mHelper.reportLocationStart(caller2, "gps", key3);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION, caller2);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION, caller2);
+        mHelper.reportLocationStart(caller2);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller2));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller2));
 
-        mHelper.reportLocationStart(caller2, "gps", key4);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION, caller2);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION, caller2);
+        mHelper.reportLocationStart(caller2);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller2));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller2));
 
-        mHelper.reportLocationStop(caller1, "gps", key2);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION, caller1);
-        mHelper.reportLocationStop(caller1, "gps", key1);
-        verify(mAppOpsHelper).finishOp(OP_MONITOR_LOCATION, caller1);
+        mHelper.reportLocationStop(caller1);
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller1));
+        mHelper.reportLocationStop(caller1);
+        verify(mAppOpsHelper).finishOp(OP_MONITOR_LOCATION, CallerIdentity.forAggregation(caller1));
 
-        mHelper.reportLocationStop(caller2, "gps", key3);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION, caller2);
-        mHelper.reportLocationStop(caller2, "gps", key4);
-        verify(mAppOpsHelper).finishOp(OP_MONITOR_LOCATION, caller2);
+        mHelper.reportLocationStop(caller2);
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_LOCATION,
+                CallerIdentity.forAggregation(caller2));
+        mHelper.reportLocationStop(caller2);
+        verify(mAppOpsHelper).finishOp(OP_MONITOR_LOCATION, CallerIdentity.forAggregation(caller2));
     }
 
     @Test
     public void testHighPowerLocationMonitoring() {
         CallerIdentity caller1 = CallerIdentity.forTest(1, 1, "test1", null);
-        Object key1 = new Object();
-        Object key2 = new Object();
         CallerIdentity caller2 = CallerIdentity.forTest(2, 2, "test2", null);
-        Object key3 = new Object();
-        Object key4 = new Object();
 
-        mHelper.reportHighPowerLocationStart(caller1, "gps", key1);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION, caller1);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller1);
+        mHelper.reportHighPowerLocationStart(caller1);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller1));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller1));
 
-        mHelper.reportHighPowerLocationStart(caller1, "gps", key2);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION, caller1);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller1);
+        mHelper.reportHighPowerLocationStart(caller1);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller1));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller1));
 
-        mHelper.reportHighPowerLocationStart(caller2, "gps", key3);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION, caller2);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller2);
+        mHelper.reportHighPowerLocationStart(caller2);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller2));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller2));
 
-        mHelper.reportHighPowerLocationStart(caller2, "gps", key4);
-        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION, caller2);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller2);
+        mHelper.reportHighPowerLocationStart(caller2);
+        verify(mAppOpsHelper).startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller2));
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller2));
 
-        mHelper.reportHighPowerLocationStop(caller1, "gps", key2);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller1);
-        mHelper.reportHighPowerLocationStop(caller1, "gps", key1);
-        verify(mAppOpsHelper).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller1);
+        mHelper.reportHighPowerLocationStop(caller1);
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller1));
+        mHelper.reportHighPowerLocationStop(caller1);
+        verify(mAppOpsHelper).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller1));
 
-        mHelper.reportHighPowerLocationStop(caller2, "gps", key3);
-        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller2);
-        mHelper.reportHighPowerLocationStop(caller2, "gps", key4);
-        verify(mAppOpsHelper).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, caller2);
+        mHelper.reportHighPowerLocationStop(caller2);
+        verify(mAppOpsHelper, never()).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller2));
+        mHelper.reportHighPowerLocationStop(caller2);
+        verify(mAppOpsHelper).finishOp(OP_MONITOR_HIGH_POWER_LOCATION,
+                CallerIdentity.forAggregation(caller2));
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index d0b2eda..890a549 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -845,6 +845,48 @@
     }
 
     @Test
+    public void testLocationMonitoring_multipleIdentities() {
+        CallerIdentity identity1 = CallerIdentity.forTest(CURRENT_USER, 1,
+                "mypackage", "attribution", "listener1");
+        CallerIdentity identity2 = CallerIdentity.forTest(CURRENT_USER, 1,
+                "mypackage", "attribution", "listener2");
+
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                IDENTITY.getPackageName())).isFalse();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                IDENTITY.getPackageName())).isFalse();
+
+        ILocationListener listener1 = createMockLocationListener();
+        LocationRequest request1 = new LocationRequest.Builder(0).setWorkSource(
+                WORK_SOURCE).build();
+        mManager.registerLocationRequest(request1, identity1, PERMISSION_FINE, listener1);
+
+        ILocationListener listener2 = createMockLocationListener();
+        LocationRequest request2 = new LocationRequest.Builder(0).setWorkSource(
+                WORK_SOURCE).build();
+        mManager.registerLocationRequest(request2, identity2, PERMISSION_FINE, listener2);
+
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                "mypackage")).isTrue();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                "mypackage")).isTrue();
+
+        mManager.unregisterLocationRequest(listener2);
+
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                "mypackage")).isTrue();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                "mypackage")).isTrue();
+
+        mManager.unregisterLocationRequest(listener1);
+
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                "mypackage")).isFalse();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                "mypackage")).isFalse();
+    }
+
+    @Test
     public void testProviderRequest() {
         assertThat(mProvider.getRequest().isActive()).isFalse();
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 63416c9..0e5640a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -47,6 +47,7 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito.any
 import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean
 import com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong
 import com.android.dx.mockito.inline.extended.ExtendedMockito.anyString
 import com.android.dx.mockito.inline.extended.ExtendedMockito.argThat
 import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
@@ -617,7 +618,7 @@
     private fun mockQueryActivities(action: String, vararg activities: ActivityInfo) {
         whenever(mocks.componentResolver.queryActivities(
                 argThat { intent: Intent? -> intent != null && (action == intent.action) },
-                nullable(), anyInt(), anyInt())) {
+                nullable(), anyLong(), anyInt())) {
             ArrayList(activities.asList().map { info: ActivityInfo? ->
                 ResolveInfo().apply { activityInfo = info }
             })
@@ -627,7 +628,7 @@
     private fun mockQueryServices(action: String, vararg services: ServiceInfo) {
         whenever(mocks.componentResolver.queryServices(
                 argThat { intent: Intent? -> intent != null && (action == intent.action) },
-                nullable(), anyInt(), anyInt())) {
+                nullable(), anyLong(), anyInt())) {
             ArrayList(services.asList().map { info ->
                 ResolveInfo().apply { serviceInfo = info }
             })
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index fe23c14..9666758 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -41,6 +41,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
@@ -316,14 +317,14 @@
         final int lastUserId = 5;
         final ServiceInfo pi = mIpm.getServiceInfo(sDefaultWallpaperComponent,
                 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, 0);
-        doReturn(pi).when(mIpm).getServiceInfo(any(), anyInt(), anyInt());
+        doReturn(pi).when(mIpm).getServiceInfo(any(), anyLong(), anyInt());
 
         final Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
         final ParceledListSlice ris =
                 mIpm.queryIntentServices(intent,
                         intent.resolveTypeIfNeeded(sContext.getContentResolver()),
                         PackageManager.GET_META_DATA, 0);
-        doReturn(ris).when(mIpm).queryIntentServices(any(), any(), anyInt(), anyInt());
+        doReturn(ris).when(mIpm).queryIntentServices(any(), any(), anyLong(), anyInt());
         doReturn(PackageManager.PERMISSION_GRANTED).when(mIpm).checkPermission(
                 eq(android.Manifest.permission.AMBIENT_WALLPAPER), any(), anyInt());
 
@@ -348,7 +349,7 @@
         final int lastUserId = 5;
         final ServiceInfo pi = mIpm.getServiceInfo(sDefaultWallpaperComponent,
                 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, 0);
-        doReturn(pi).when(mIpm).getServiceInfo(any(), anyInt(), anyInt());
+        doReturn(pi).when(mIpm).getServiceInfo(any(), anyLong(), anyInt());
 
         final Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
         final ParceledListSlice ris =
@@ -362,7 +363,7 @@
             mService.switchUser(userId, null);
             verifyLastWallpaperData(userId, sImageWallpaperComponentName);
             // Simulate user unlocked
-            doReturn(ris).when(mIpm).queryIntentServices(any(), any(), anyInt(), eq(userId));
+            doReturn(ris).when(mIpm).queryIntentServices(any(), any(), anyLong(), eq(userId));
             mService.onUnlockUser(userId);
             verifyLastWallpaperData(userId, sDefaultWallpaperComponent);
             verifyCurrentSystemData(userId);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 0863f9e..ec1a0c2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -155,7 +155,7 @@
         verify(mScreenMagnificationController, never()).reset(anyInt(),
                 any(MagnificationAnimationCallback.class));
         verify(mMockConnection.getConnection(), never()).enableWindowMagnification(anyInt(),
-                anyFloat(), anyFloat(), anyFloat(),
+                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(),
                 nullable(IRemoteMagnificationAnimationCallback.class));
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
index 2a53504..0659a60 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
@@ -93,7 +93,7 @@
             final float scale = invocation.getArgument(1);
             mScale = Float.isNaN(scale) ? mScale : scale;
             computeMirrorWindowFrame(invocation.getArgument(2), invocation.getArgument(3));
-            setAnimationCallback(invocation.getArgument(4));
+            setAnimationCallback(invocation.getArgument(6));
             computeSourceBounds();
             mHasPendingCallback = true;
             if (!mSuspendCallback) {
@@ -101,7 +101,7 @@
             }
             return null;
         }).when(mConnection).enableWindowMagnification(anyInt(), anyFloat(), anyFloat(), anyFloat(),
-                nullable(IRemoteMagnificationAnimationCallback.class));
+                anyFloat(), anyFloat(), nullable(IRemoteMagnificationAnimationCallback.class));
     }
 
     private void stubDisableWindowMagnification() throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
index 1638563..3822dc3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
@@ -67,7 +67,7 @@
     @Test
     public void enableWindowMagnification() throws RemoteException {
         mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f,
-                mAnimationCallback);
+                0f, 0f, mAnimationCallback);
 
         verify(mAnimationCallback).onResult(true);
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index 1b8aff5..b807c11 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -24,6 +24,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.testing.TestableContext;
 import android.util.DebugUtils;
 import android.view.InputDevice;
@@ -58,10 +59,11 @@
     public static final int STATE_SHOW_MAGNIFIER_SHORTCUT = 2;
     public static final int STATE_TWO_FINGERS_DOWN = 3;
     public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP = 4;
+    public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD = 5;
     //TODO: Test it after can injecting Handler to GestureMatcher is available.
 
     public static final int FIRST_STATE = STATE_IDLE;
-    public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP;
+    public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD;
 
     // Co-prime x and y, to potentially catch x-y-swapped errors
     public static final float DEFAULT_TAP_X = 301;
@@ -178,6 +180,12 @@
                         == mWindowMagnificationGestureHandler.mDetectingState, state);
             }
                 break;
+            case STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
+                check(isWindowMagnifierEnabled(DISPLAY_0), state);
+                check(mWindowMagnificationGestureHandler.mCurrentState
+                        == mWindowMagnificationGestureHandler.mViewportDraggingState, state);
+            }
+            break;
             case STATE_TWO_FINGERS_DOWN: {
                 check(isWindowMagnifierEnabled(DISPLAY_0), state);
                 check(mWindowMagnificationGestureHandler.mCurrentState
@@ -229,6 +237,13 @@
                     tap();
                 }
                 break;
+                case STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
+                    // Perform triple tap and hold gesture
+                    tap();
+                    tap();
+                    tapAndHold();
+                }
+                break;
                 default:
                     throw new IllegalArgumentException("Illegal state: " + state);
             }
@@ -262,6 +277,10 @@
                 tap();
             }
             break;
+            case STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
+                send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
+            }
+            break;
             default:
                 throw new IllegalArgumentException("Illegal state: " + state);
         }
@@ -308,6 +327,11 @@
         send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
     }
 
+    private void tapAndHold() {
+        send(downEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
+        SystemClock.sleep(ViewConfiguration.getLongPressTimeout() + 100);
+    }
+
     private String stateDump() {
         return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 02c0aca..85512f3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -143,8 +143,7 @@
      * new connection.
      */
     @Test
-    public void
-            setSecondConnectionAndFormerConnectionBinderDead_hasWrapperAndNotCallUnlinkToDeath()
+    public void setSecondConnectionAndFormerConnectionBinderDead_hasWrapperAndNotCallUnlinkToDeath()
             throws RemoteException {
         mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
         MockWindowMagnificationConnection secondConnection =
@@ -177,7 +176,7 @@
         mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f);
 
         verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(2f),
-                eq(200f), eq(300f), notNull());
+                eq(200f), eq(300f), eq(0f), eq(0f), notNull());
     }
 
     @Test
@@ -189,7 +188,8 @@
                 mAnimationCallback);
 
         verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(2f),
-                eq(200f), eq(300f), any(IRemoteMagnificationAnimationCallback.class));
+                eq(200f), eq(300f), eq(0f), eq(0f),
+                any(IRemoteMagnificationAnimationCallback.class));
         verify(mAnimationCallback).onResult(true);
     }
 
@@ -411,6 +411,34 @@
     }
 
     @Test
+    public void centerGetter_enabledOnTestDisplayWindowAtCenter_expectedValues()
+            throws RemoteException {
+        mWindowMagnificationManager.requestConnection(true);
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+                100f, 200f, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
+
+        assertEquals(mWindowMagnificationManager.getCenterX(TEST_DISPLAY), 100f);
+        assertEquals(mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 200f);
+
+        verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(3f),
+                eq(100f), eq(200f), eq(0f), eq(0f), notNull());
+    }
+
+    @Test
+    public void centerGetter_enabledOnTestDisplayWindowAtLeftTop_expectedValues()
+            throws RemoteException {
+        mWindowMagnificationManager.requestConnection(true);
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+                100f, 200f, WindowMagnificationManager.WINDOW_POSITION_AT_TOP_LEFT);
+
+        assertEquals(mWindowMagnificationManager.getCenterX(TEST_DISPLAY), 100f);
+        assertEquals(mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 200f);
+
+        verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(3f),
+                eq(100f), eq(200f), eq(-1f), eq(-1f), notNull());
+    }
+
+    @Test
     public void onDisplayRemoved_enabledOnTestDisplay_disabled() {
         mWindowMagnificationManager.requestConnection(true);
         mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 100f, 200f);
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 1c49e6e..e40f543 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -29,7 +29,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.intThat;
+import static org.mockito.ArgumentMatchers.longThat;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -135,7 +135,7 @@
         packages.add(makePackageInfo(PACKAGE_NAME_2));
         packages.add(makePackageInfo(PACKAGE_NAME_3));
         doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
-                intThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
+                longThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
         mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
         UserInfo userInfo = addUser(USER_ID_1);
@@ -412,7 +412,7 @@
         UserInfo userInfo = new UserInfo(userId, "user_" + userId, 0 /* flags */);
         mUserInfos.add(userInfo);
         doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
-                .getInstalledPackages(intThat(arg -> (arg & MATCH_ANY_USER) == 0), eq(userId));
+                .getInstalledPackages(longThat(arg -> (arg & MATCH_ANY_USER) == 0), eq(userId));
         return userInfo;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index e3e3900..d192697 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -143,8 +143,8 @@
 
         final ClientMonitorCallbackConverter listener1 = mock(ClientMonitorCallbackConverter.class);
 
-        final BiometricPromptClientMonitor client1 =
-                new BiometricPromptClientMonitor(mContext, mToken, lazyDaemon1, listener1);
+        final TestAuthenticationClient client1 =
+                new TestAuthenticationClient(mContext, lazyDaemon1, mToken, listener1);
         final TestClientMonitor client2 = new TestClientMonitor(mContext, mToken, lazyDaemon2);
 
         final BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
@@ -180,8 +180,8 @@
     @Test
     public void testCancelNotInvoked_whenOperationWaitingForCookie() {
         final HalClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> mock(Object.class);
-        final BiometricPromptClientMonitor client1 = new BiometricPromptClientMonitor(mContext,
-                mToken, lazyDaemon1, mock(ClientMonitorCallbackConverter.class));
+        final TestAuthenticationClient client1 = new TestAuthenticationClient(mContext,
+                lazyDaemon1, mToken, mock(ClientMonitorCallbackConverter.class));
         final BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
 
         // Schedule a BiometricPrompt authentication request
@@ -195,6 +195,8 @@
         // should go back to idle, since in this case the framework has not even requested the HAL
         // to authenticate yet.
         mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */);
+        assertTrue(client1.isAlreadyDone());
+        assertTrue(client1.mDestroyed);
         assertNull(mScheduler.mCurrentOperation);
     }
 
@@ -316,6 +318,10 @@
                 eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
                 eq(0) /* vendorCode */);
         assertNull(mScheduler.getCurrentClient());
+        assertTrue(client1.isAlreadyDone());
+        assertTrue(client1.mDestroyed);
+        assertTrue(client2.isAlreadyDone());
+        assertTrue(client2.mDestroyed);
     }
 
     @Test
@@ -465,39 +471,9 @@
         return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer));
     }
 
-    private static class BiometricPromptClientMonitor extends AuthenticationClient<Object> {
-
-        public BiometricPromptClientMonitor(@NonNull Context context, @NonNull IBinder token,
-                @NonNull LazyDaemon<Object> lazyDaemon, ClientMonitorCallbackConverter listener) {
-            super(context, lazyDaemon, token, listener, 0 /* targetUserId */, 0 /* operationId */,
-                    false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
-                    TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
-                    0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
-                    false /* isKeyguard */, true /* shouldVibrate */,
-                    false /* isKeyguardBypassEnabled */);
-        }
-
-        @Override
-        protected void stopHalOperation() {
-        }
-
-        @Override
-        protected void startHalOperation() {
-        }
-
-        @Override
-        protected void handleLifecycleAfterAuth(boolean authenticated) {
-
-        }
-
-        @Override
-        public boolean wasUserDetected() {
-            return false;
-        }
-    }
-
     private static class TestAuthenticationClient extends AuthenticationClient<Object> {
         int mNumCancels = 0;
+        boolean mDestroyed = false;
 
         public TestAuthenticationClient(@NonNull Context context,
                 @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token,
@@ -530,6 +506,13 @@
             return false;
         }
 
+        @Override
+        public void destroy() {
+            mDestroyed = true;
+            super.destroy();
+        }
+
+        @Override
         public void cancel() {
             mNumCancels++;
             super.cancel();
@@ -595,6 +578,7 @@
 
         @Override
         public void destroy() {
+            super.destroy();
             mDestroyed = true;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 2777bdf..3c809f9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1735,11 +1735,11 @@
         pi.applicationInfo.flags = flags;
         doReturn(pi).when(getServices().ipackageManager).getPackageInfo(
                 eq(packageName),
-                anyInt(),
+                anyLong(),
                 eq(userId));
         doReturn(pi.applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
                 eq(packageName),
-                anyInt(),
+                anyLong(),
                 eq(userId));
         doReturn(true).when(getServices().ipackageManager).isPackageAvailable(packageName, userId);
         // Setup application UID with the PackageManager
@@ -4708,11 +4708,11 @@
         // Ensure packages are *not* flagged as test_only.
         doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
                 eq(admin1.getPackageName()),
-                anyInt(),
+                anyLong(),
                 eq(CALLER_USER_HANDLE));
         doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
                 eq(admin2.getPackageName()),
-                anyInt(),
+                anyLong(),
                 eq(CALLER_USER_HANDLE));
 
         // Initial state is disabled.
@@ -7078,7 +7078,7 @@
 
         doReturn(ai).when(getServices().ipackageManager).getApplicationInfo(
                 eq(admin1.getPackageName()),
-                anyInt(),
+                anyLong(),
                 eq(CALLER_USER_HANDLE));
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index fe0df58..b8824c3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -21,7 +21,6 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
@@ -221,7 +220,7 @@
 
         doReturn(ai).when(mServices.ipackageManager).getApplicationInfo(
                 eq(admin.getPackageName()),
-                anyInt(),
+                anyLong(),
                 eq(UserHandle.getUserId(packageUid)));
 
         // Set up queryBroadcastReceivers().
@@ -248,7 +247,7 @@
 
         doReturn(aci).when(mServices.ipackageManager).getReceiverInfo(
                 eq(admin),
-                anyInt(),
+                anyLong(),
                 eq(UserHandle.getUserId(packageUid)));
 
         doReturn(new String[] {admin.getPackageName()}).when(mServices.ipackageManager)
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
index b3a513f..ddc58b2 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
@@ -110,7 +111,7 @@
     @Test(expected = SecurityException.class)
     public void testSetApplicationLocales_arbitraryAppWithoutPermissions_fails() throws Exception {
         doReturn(DEFAULT_UID)
-                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyInt(), anyInt());
+                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
         setUpFailingPermissionCheckFor(Manifest.permission.CHANGE_CONFIGURATION);
 
         try {
@@ -153,7 +154,7 @@
     @Test
     public void testSetApplicationLocales_arbitraryAppWithPermission_succeeds() throws Exception {
         doReturn(DEFAULT_UID)
-                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyInt(), anyInt());
+                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
         // if package is not owned by the caller, the calling app should have the following
         //   permission. We will mock this to succeed to imitate that.
         setUpPassingPermissionCheckFor(Manifest.permission.CHANGE_CONFIGURATION);
@@ -168,7 +169,7 @@
     @Test
     public void testSetApplicationLocales_callerOwnsPackage_succeeds() throws Exception {
         doReturn(Binder.getCallingUid())
-                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyInt(), anyInt());
+                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
 
         mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
                 DEFAULT_LOCALES);
@@ -179,7 +180,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void testSetApplicationLocales_invalidPackageOrUserId_fails() throws Exception {
         doReturn(INVALID_UID)
-                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyInt(), anyInt());
+                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
         try {
             mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
                     LocaleList.getEmptyLocaleList());
@@ -192,7 +193,7 @@
     @Test(expected = SecurityException.class)
     public void testGetApplicationLocales_arbitraryAppWithoutPermission_fails() throws Exception {
         doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
-                .getPackageUid(anyString(), anyInt(), anyInt());
+                .getPackageUid(anyString(), anyLong(), anyInt());
         setUpFailingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
 
         try {
@@ -210,7 +211,7 @@
             throws Exception {
         // any valid app calling for its own package or having appropriate permission
         doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
-                .getPackageUid(anyString(), anyInt(), anyInt());
+                .getPackageUid(anyString(), anyLong(), anyInt());
         setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
         doReturn(null)
                 .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
@@ -225,7 +226,7 @@
     public void testGetApplicationLocales_appSpecificLocalesAbsent_returnsEmptyList()
             throws Exception {
         doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
-                .getPackageUid(anyString(), anyInt(), anyInt());
+                .getPackageUid(anyString(), anyLong(), anyInt());
         setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
         doReturn(new PackageConfig(/* nightMode = */ 0, /* locales = */ null))
                 .when(mMockActivityTaskManager).getApplicationConfig(any(), anyInt());
@@ -240,7 +241,7 @@
     public void testGetApplicationLocales_callerOwnsAppAndConfigPresent_returnsLocales()
             throws Exception {
         doReturn(Binder.getCallingUid()).when(mMockPackageManagerInternal)
-                .getPackageUid(anyString(), anyInt(), anyInt());
+                .getPackageUid(anyString(), anyLong(), anyInt());
         doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
                 .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
 
@@ -254,7 +255,7 @@
     public void testGetApplicationLocales_arbitraryCallerWithPermissions_returnsLocales()
             throws Exception {
         doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
-                .getPackageUid(anyString(), anyInt(), anyInt());
+                .getPackageUid(anyString(), anyLong(), anyInt());
         setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
         doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
                 .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
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 f45c869..3722ba4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
@@ -2357,7 +2358,7 @@
 
     protected void prepareIntentActivities(ComponentName cn) {
         when(mMockPackageManagerInternal.queryIntentActivities(
-                anyOrNull(Intent.class), anyStringOrNull(), anyInt(), anyInt(), anyInt()))
+                anyOrNull(Intent.class), anyStringOrNull(), anyLong(), anyInt(), anyInt()))
                 .thenReturn(Collections.singletonList(
                         ri(cn.getPackageName(), cn.getClassName(), false, 0)));
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/BundleUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/BundleUtilsTest.java
index 764c504..6245f82 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BundleUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BundleUtilsTest.java
@@ -22,8 +22,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.Bundle;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.BundleUtils;
@@ -35,6 +36,7 @@
  * Build/Install/Run:
  * atest com.android.server.pm.BundleUtilsTest
  */
+@Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BundleUtilsTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
index b228c83..54ab133 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
@@ -32,6 +32,7 @@
 import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.pkg.PackageUserStateImpl;
@@ -40,6 +41,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
+@Presubmit
 public class CompatibilityModeTest {
 
     private boolean mCompatibilityModeEnabled;;
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index e811c1f..3cb5d5f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -3,9 +3,10 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doAnswer;
@@ -14,7 +15,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-
 import static org.testng.Assert.assertThrows;
 
 import android.Manifest;
@@ -581,7 +581,7 @@
     private void mockAppsInstalled(String packageName, int user, boolean installed) {
         when(mPackageManagerInternal.getPackageInfo(
                 eq(packageName),
-                anyInt(),
+                anyLong(),
                 anyInt(),
                 eq(user)))
                 .thenReturn(installed ? createInstalledPackageInfo() : null);
@@ -604,7 +604,7 @@
         mActivityInfo = activityInfo;
 
         when(mPackageManagerInternal.queryIntentActivities(
-                any(Intent.class), nullable(String.class), anyInt(), anyInt(), anyInt()))
+                any(Intent.class), nullable(String.class), anyLong(), anyInt(), anyInt()))
                 .thenReturn(Collections.singletonList(resolveInfo));
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 9631863..6b6d84a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -20,6 +20,7 @@
 import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
 
 import android.content.pm.Signature;
+import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -33,6 +34,7 @@
 import java.security.PublicKey;
 import java.security.cert.CertificateException;
 
+@Presubmit
 public class KeySetManagerServiceTest extends AndroidTestCase {
 
     private WatchedArrayMap<String, PackageSetting> mPackagesMap;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
index 6a9ef8a..9ea7907 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageManager;
+import android.platform.test.annotations.Presubmit;
 import android.test.InstrumentationTestCase;
 
 import com.android.frameworks.servicestests.R;
@@ -30,6 +31,7 @@
 import java.util.Collections;
 import java.util.List;
 
+@Presubmit
 public class ModuleInfoProviderTest extends InstrumentationTestCase {
 
     @Mock private ApexManager mApexManager;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 6a85c8b..b81a4ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -37,6 +37,7 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
 import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
@@ -69,15 +70,21 @@
 // atest PackageManagerServiceTest
 // runtest -c com.android.server.pm.PackageManagerServiceTest frameworks-services
 // bit FrameworksServicesTests:com.android.server.pm.PackageManagerServiceTest
+@Postsubmit
 @RunWith(AndroidJUnit4.class)
 public class PackageManagerServiceTest {
 
+    private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
+
     private static final String TEST_DATA_PATH = "/data/local/tmp/servicestests/";
     private static final String TEST_APP_APK = "StubTestApp.apk";
     private static final String TEST_PKG_NAME = "com.android.servicestests.apps.stubapp";
 
+    private IPackageManager mIPackageManager;
+
     @Before
     public void setUp() throws Exception {
+        mIPackageManager = AppGlobals.getPackageManager();
     }
 
     @After
@@ -620,20 +627,19 @@
 
     @Test
     public void testInstallReason_afterUpdate_keepUnchanged() throws Exception {
-        final IPackageManager pm = AppGlobals.getPackageManager();
         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
         try {
             // Try to install test APK with reason INSTALL_REASON_POLICY
             runShellCommand("pm install --install-reason 1 " + testApk);
             assertWithMessage("The install reason of test APK is incorrect.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
-                    PackageManager.INSTALL_REASON_POLICY);
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME,
+                            UserHandle.myUserId())).isEqualTo(PackageManager.INSTALL_REASON_POLICY);
 
             // Try to update test APK with different reason INSTALL_REASON_USER
             runShellCommand("pm install --install-reason 4 " + testApk);
             assertWithMessage("The install reason should keep unchanged after update.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
-                    PackageManager.INSTALL_REASON_POLICY);
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME,
+                            UserHandle.myUserId())).isEqualTo(PackageManager.INSTALL_REASON_POLICY);
         } finally {
             runShellCommand("pm uninstall " + TEST_PKG_NAME);
         }
@@ -642,7 +648,6 @@
     @Test
     public void testInstallReason_userRemainsUninstalled_keepUnknown() throws Exception {
         Assume.assumeTrue(UserManager.supportsMultipleUsers());
-        final IPackageManager pm = AppGlobals.getPackageManager();
         final UserManager um = UserManager.get(
                 InstrumentationRegistry.getInstrumentation().getContext());
         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
@@ -651,21 +656,21 @@
             // Try to install test APK with reason INSTALL_REASON_POLICY
             runShellCommand("pm install --install-reason 1 " + testApk);
             assertWithMessage("The install reason of test APK is incorrect.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
-                    PackageManager.INSTALL_REASON_POLICY);
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME,
+                            UserHandle.myUserId())).isEqualTo(PackageManager.INSTALL_REASON_POLICY);
 
             // Create and start the 2nd user.
             userId = um.createUser("Test User", 0 /* flags */).getUserHandle().getIdentifier();
             runShellCommand("am start-user -w " + userId);
             // Since the test APK isn't installed on the 2nd user, the reason should be unknown.
             assertWithMessage("The install reason in 2nd user should be unknown.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
                     PackageManager.INSTALL_REASON_UNKNOWN);
 
             // Try to update test APK with different reason INSTALL_REASON_USER
             runShellCommand("pm install --install-reason 4 " + testApk);
             assertWithMessage("The install reason in 2nd user should keep unknown.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
                     PackageManager.INSTALL_REASON_UNKNOWN);
         } finally {
             runShellCommand("pm uninstall " + TEST_PKG_NAME);
@@ -678,7 +683,6 @@
     @Test
     public void testInstallReason_installForAllUsers_sameReason() throws Exception {
         Assume.assumeTrue(UserManager.supportsMultipleUsers());
-        final IPackageManager pm = AppGlobals.getPackageManager();
         final UserManager um = UserManager.get(
                 InstrumentationRegistry.getInstrumentation().getContext());
         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
@@ -691,8 +695,9 @@
             // Try to install test APK to all users with reason INSTALL_REASON_POLICY
             runShellCommand("pm install --install-reason 1 " + testApk);
             assertWithMessage("The install reason is inconsistent across users.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
-                    pm.getInstallReason(TEST_PKG_NAME, userId));
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME,
+                            UserHandle.myUserId())).isEqualTo(
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME, userId));
         } finally {
             runShellCommand("pm uninstall " + TEST_PKG_NAME);
             if (userId != UserHandle.USER_NULL) {
@@ -704,7 +709,6 @@
     @Test
     public void testInstallReason_installSeparately_withSeparatedReason() throws Exception {
         Assume.assumeTrue(UserManager.supportsMultipleUsers());
-        final IPackageManager pm = AppGlobals.getPackageManager();
         final UserManager um = UserManager.get(
                 InstrumentationRegistry.getInstrumentation().getContext());
         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
@@ -717,13 +721,13 @@
             // Try to install test APK on the current user with reason INSTALL_REASON_POLICY
             runShellCommand("pm install --user cur --install-reason 1 " + testApk);
             assertWithMessage("The install reason on the current user is incorrect.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
-                    PackageManager.INSTALL_REASON_POLICY);
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME,
+                            UserHandle.myUserId())).isEqualTo(PackageManager.INSTALL_REASON_POLICY);
 
             // Try to install test APK on the 2nd user with reason INSTALL_REASON_USER
             runShellCommand("pm install --user " + userId + " --install-reason 4 " + testApk);
             assertWithMessage("The install reason on the 2nd user is incorrect.").that(
-                    pm.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
+                    mIPackageManager.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
                     PackageManager.INSTALL_REASON_USER);
         } finally {
             runShellCommand("pm uninstall " + TEST_PKG_NAME);
@@ -732,4 +736,26 @@
             }
         }
     }
+
+    @Test
+    public void testSetSplashScreenTheme_samePackage_succeeds() throws Exception {
+        mIPackageManager.setSplashScreenTheme(PACKAGE_NAME, null /* themeName */,
+                UserHandle.myUserId());
+        // Invoking setSplashScreenTheme on the same package shouldn't get any exception.
+    }
+
+    @Test
+    public void testSetSplashScreenTheme_differentPackage_fails() throws Exception {
+        final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
+        try {
+            runShellCommand("pm install " + testApk);
+            mIPackageManager.setSplashScreenTheme(TEST_PKG_NAME, null /* themeName */,
+                    UserHandle.myUserId());
+            fail("setSplashScreenTheme did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        } finally {
+            runShellCommand("pm uninstall " + TEST_PKG_NAME);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ab37e9b..a9a3469 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -47,6 +47,7 @@
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Log;
@@ -91,6 +92,7 @@
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageManagerSettingsTests {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index b6d4b31..7e4474f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.pm.Signature;
 import android.content.pm.SigningDetails;
+import android.platform.test.annotations.Presubmit;
 import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
@@ -44,6 +45,7 @@
 import java.util.Map;
 import java.util.Set;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class PackageSignaturesTest {
     private static final String TEST_RESOURCES_FOLDER = "PackageSignaturesTest";
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index c9f3cb2..828d419c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.overlay.OverlayPaths;
 import android.os.PersistableBundle;
+import android.platform.test.annotations.Presubmit;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -41,6 +42,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageUserStateTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
index 1fff4f0..ecf7803 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
@@ -18,8 +18,10 @@
 
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
 
+@Presubmit
 public class PackageVerificationStateTest extends AndroidTestCase {
     private static final int REQUIRED_UID = 1948;
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java b/services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java
index b73c9ea..e7adf7b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -37,6 +38,7 @@
 import java.util.List;
 
 /** Test for {@link RestrictionsSet}. */
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class RestrictionsSetTest {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index ec5228f..32a88bd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -95,13 +95,15 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.UserHandle;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.ShortcutService.ConfigConstants;
 import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
@@ -135,6 +137,7 @@
  adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 \
  -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java
index e92c849..57ada9b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java
@@ -15,10 +15,13 @@
  */
 package com.android.server.pm;
 
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
-        .assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.LauncherActivityInfo;
@@ -26,9 +29,9 @@
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager;
 import android.os.Process;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
 
-import static org.mockito.Mockito.*;
+import androidx.test.filters.SmallTest;
 
 /**
  * Tests for {@link ShortcutManager#createShortcutResultIntent(ShortcutInfo)} and relevant APIs.
@@ -39,6 +42,7 @@
  adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest10 \
  -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest10 extends BaseShortcutManagerTest {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java
index c8a4052..98fa2d6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java
@@ -30,6 +30,7 @@
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.ShortcutInfo;
 import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
 
 import com.android.server.pm.ShortcutService.ConfigConstants;
 
@@ -42,6 +43,7 @@
  *
  atest -c com.android.server.pm.ShortcutManagerTest11
  */
+@Presubmit
 public class ShortcutManagerTest11 extends BaseShortcutManagerTest {
 
     private static final ShortcutQuery QUERY_MATCH_ALL = createShortcutQuery(
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 90a1277..408d2c5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -43,8 +43,10 @@
 import android.net.Uri;
 import android.os.PersistableBundle;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.ShortcutUser.PackageWithUser;
@@ -64,6 +66,7 @@
  adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest2 \
  -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
     // ShortcutInfo tests
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
index ba26f79..43e527c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
@@ -21,7 +21,9 @@
 
 import android.content.ComponentName;
 import android.content.pm.ShortcutInfo;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.ShortcutService.ConfigConstants;
@@ -31,6 +33,7 @@
 /**
  * Tests related to shortcut rank auto-adjustment.
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
index 7546c43..11a2a8a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
@@ -24,15 +24,17 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
 import android.util.Xml;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ShortcutManagerTest4 extends BaseShortcutManagerTest {
@@ -134,4 +136,4 @@
                     });
         });
     }
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
index 203b2ca..400d3a8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
@@ -25,7 +25,9 @@
 import android.content.pm.ShortcutServiceInternal;
 import android.content.res.XmlResourceParser;
 import android.os.Looper;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.LocalServices;
 
@@ -38,6 +40,7 @@
  * All the tests here actually talks to the real IPackageManager, so we can't test complicated
  * cases.  Instead we just make sure they all work reasonably without at least crashing.
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest5 extends BaseShortcutManagerTest {
     private ShortcutService mShortcutService;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
index 63df4bc..6c10bfd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
@@ -15,12 +15,15 @@
  */
 package com.android.server.pm;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
 
 /**
  * Tests for {@link ShortcutService#hasShortcutHostPermissionInner}, which includes
  * {@link ShortcutService#getDefaultLauncher}.
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest6 extends BaseShortcutManagerTest {
     public void testHasShortcutHostPermissionInner_with3pLauncher_complicated() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
index b21b049..b2fd8aa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
@@ -33,7 +33,9 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.ShortcutService.ConfigConstants;
@@ -48,6 +50,7 @@
  *
  * Launcher related commands are tested in
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
index 58e00f2..2293808 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -40,11 +40,13 @@
 import android.content.pm.ShortcutManager;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.servicestests.R;
 
 import org.mockito.ArgumentCaptor;
@@ -63,6 +65,7 @@
  * - Reading icons from requested shortcuts.
  * - Invalid pre-approved token.
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest8 extends BaseShortcutManagerTest {
     private ShortcutRequestPinProcessor mProcessor;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
index 55b4b93..a47a8df 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
@@ -32,7 +32,9 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.PinItemRequest;
 import android.os.UserHandle;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
 
 import org.mockito.ArgumentCaptor;
 
@@ -46,6 +48,7 @@
  adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest9 \
  -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
  */
+@Presubmit
 @SmallTest
 public class ShortcutManagerTest9 extends BaseShortcutManagerTest {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java
index 826a8d4..4af91c6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertNull;
 
 import android.content.pm.SuspendDialogInfo;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,6 +32,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class SuspendDialogInfoTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
new file mode 100644
index 0000000..85a73bb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
@@ -0,0 +1,41 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.pm."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.pm."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Postsubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java b/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
index 7916bd3..a4afe09 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
@@ -24,6 +24,7 @@
 import android.content.pm.UserInfo;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -42,6 +43,7 @@
  * To run the test:
  * bit FrameworksServicesTests:com.android.server.pm.UserLifecycleStressTest
  */
+@Postsubmit
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class UserLifecycleStressTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
index 35c513f..fdf94be 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
@@ -27,6 +27,7 @@
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
@@ -48,6 +49,7 @@
  * runtest -c com.android.server.pm.UserManagerServiceCreateProfileTest frameworks-services
  * </pre>
  */
+@Postsubmit
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class UserManagerServiceCreateProfileTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceIdRecyclingTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceIdRecyclingTest.java
index b0423bf..1f4c9f8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceIdRecyclingTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceIdRecyclingTest.java
@@ -23,6 +23,7 @@
 import android.app.PropertyInvalidatedCache;
 import android.content.pm.UserInfo;
 import android.os.Looper;
+import android.platform.test.annotations.Postsubmit;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
@@ -45,6 +46,7 @@
  * -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
  * </pre>
  */
+@Postsubmit
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class UserManagerServiceIdRecyclingTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6c1c019..34b40c7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -22,18 +22,20 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
 import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 import android.util.AtomicFile;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.Arrays;
 
+@Postsubmit
 @SmallTest
 public class UserManagerServiceTest extends AndroidTestCase {
     private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index dfc25e0..92fddc7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -46,6 +46,7 @@
 import android.os.Parcel;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
 import android.text.TextUtils;
 
 import androidx.test.InstrumentationRegistry;
@@ -69,6 +70,7 @@
  * runtest -c com.android.server.pm.UserManagerServiceUserInfoTest frameworks-services
  * </pre>
  */
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class UserManagerServiceUserInfoTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index f1acc66..971b036 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -39,6 +39,7 @@
 import android.content.res.XmlResourceParser;
 import android.os.Bundle;
 import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
 import android.util.ArrayMap;
 
 import androidx.test.InstrumentationRegistry;
@@ -58,6 +59,7 @@
  *
  * <p>Run with: atest UserManagerServiceUserTypeTest
  */
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class UserManagerServiceUserTypeTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index ea0c073..cf6165f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -35,14 +35,15 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
 import android.provider.Settings;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Slog;
 
 import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.google.common.collect.Range;
@@ -63,6 +64,7 @@
 import javax.annotation.concurrent.GuardedBy;
 
 /** Test {@link UserManager} functionality. */
+@Postsubmit
 @RunWith(AndroidJUnit4.class)
 public final class UserManagerTest {
     // Taken from UserManagerService
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index ddf0cd0..07a5303 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -22,10 +22,12 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.SparseArray;
 
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
  *
@@ -37,6 +39,7 @@
      -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
  * </pre>
  */
+@Presubmit
 @SmallTest
 public class UserRestrictionsUtilsTest extends AndroidTestCase {
     public void testNonNull() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index b11bb85..ba7a103 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -43,6 +43,7 @@
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
 import android.support.test.uiautomator.UiDevice;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -76,6 +77,7 @@
  * atest com.android.server.pm.UserSystemPackageInstallerTest
  * </pre>
  */
+@Postsubmit
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class UserSystemPackageInstallerTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java b/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java
index b2c3002..95af1e1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java
@@ -20,6 +20,7 @@
 
 import android.content.ComponentName;
 import android.content.IntentFilter;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
@@ -29,6 +30,7 @@
 
 import java.util.Iterator;
 
+@Presubmit
 @SmallTest
 public class WatchedIntentHandlingTest {
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
index fdb6e9f5..a16ecb1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
@@ -18,6 +18,8 @@
 
 import static org.mockito.Mockito.inOrder;
 
+import android.platform.test.annotations.Presubmit;
+
 import com.android.internal.art.ArtStatsLog;
 import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
 
@@ -44,6 +46,7 @@
  *
  * Run with "atest ArtStatsLogUtilsTest".
  */
+@Presubmit
 @RunWith(JUnit4.class)
 public final class ArtStatsLogUtilsTest {
     private static final String TAG = ArtStatsLogUtilsTest.class.getSimpleName();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 2a7a2ff..b7b55ba 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -30,6 +30,7 @@
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.os.FileUtils;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -61,6 +62,7 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
+@Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DexMetadataHelperTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index bc84e35..d5893c8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -23,6 +23,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.platform.test.annotations.Presubmit;
+
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -32,6 +34,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DexoptOptionsTests {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 34cefec..1dcb0b7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -24,6 +24,7 @@
 
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ParsingPackage;
+import android.platform.test.annotations.Presubmit;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
@@ -46,6 +47,7 @@
 import java.util.Collections;
 import java.util.List;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DexoptUtilsTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java
index 7992ba3..d55f967 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageInfo;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -51,6 +52,7 @@
 import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Stubber;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DynamicCodeLoggerTests {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index 3450710..c98e7c3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -28,6 +28,7 @@
 import static org.junit.Assert.fail;
 
 import android.os.Build;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -49,6 +50,7 @@
 import java.util.Map;
 import java.util.Set;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageDexUsageTests {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDynamicCodeLoadingTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDynamicCodeLoadingTests.java
index f4cdc8c..e075379 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDynamicCodeLoadingTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDynamicCodeLoadingTests.java
@@ -30,6 +30,8 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
+import android.platform.test.annotations.Presubmit;
+
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -50,6 +52,7 @@
 import java.util.Objects;
 import java.util.Set;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageDynamicCodeLoadingTests {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
index 51c268e..4059a49 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -16,17 +16,18 @@
 
 package com.android.server.pm.parsing
 
+import android.Manifest
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
 import android.content.pm.PackageParser
 import android.platform.test.annotations.Postsubmit
+import com.android.internal.util.ArrayUtils
 import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
 import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -91,9 +92,18 @@
                     listOf(it.configPreferences, it.reqFeatures, it.featureGroups)
                 },
                 pkgInfo(PackageManager.GET_PERMISSIONS) {
-                    listOf(it.permissions, it.requestedPermissions, it.requestedPermissionsFlags)
+                    listOf(
+                        it.permissions,
+                        // Strip compatibility permission added in T
+                        it.requestedPermissions?.filter { x ->
+                            x != Manifest.permission.POST_NOTIFICATIONS
+                        }?.ifEmpty { null }?.toTypedArray(),
+                        // Strip the flag from compatibility permission added in T
+                        it.requestedPermissionsFlags?.filterIndexed { index, _ ->
+                            index != ArrayUtils.indexOf(it.requestedPermissions,
+                                                        Manifest.permission.POST_NOTIFICATIONS)
+                        }?.ifEmpty { null }?.toTypedArray())
                 },
-
                 appInfo(PackageManager.GET_META_DATA) { listOf(it.metaData) },
                 appInfo(PackageManager.GET_SHARED_LIBRARY_FILES) {
                     listOf(it.sharedLibraryFiles, it.sharedLibraryFiles)
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index df8786f..122661e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.pm.parsing
 
+import android.Manifest
 import android.content.Context
 import android.content.pm.ActivityInfo
 import android.content.pm.ApplicationInfo
@@ -34,6 +35,7 @@
 import android.os.Process
 import android.util.SparseArray
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.internal.util.ArrayUtils
 import com.android.server.pm.PackageManagerService
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
@@ -145,8 +147,8 @@
             flags: Int = 0,
             userId: Int = 0
         ): ApplicationInfo? {
-            return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyUserState, userId,
-                    mockPkgSetting(pkg))
+            return PackageInfoUtils.generateApplicationInfo(pkg, flags.toLong(), dummyUserState,
+                userId, mockPkgSetting(pkg))
         }
 
         fun newAppInfoWithoutState(
@@ -154,8 +156,8 @@
             flags: Int = 0,
             userId: Int = 0
         ): ApplicationInfo? {
-            return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyUserState, userId,
-                    mockPkgSetting(pkg))
+            return PackageInfoUtils.generateApplicationInfo(pkg, flags.toLong(), dummyUserState,
+                userId, mockPkgSetting(pkg))
         }
 
         fun oldPackageInfo(pkg: PackageParser.Package, flags: Int = 0): PackageInfo? {
@@ -164,7 +166,7 @@
         }
 
         fun newPackageInfo(pkg: AndroidPackage, flags: Int = 0): PackageInfo? {
-            return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(),
+            return PackageInfoUtils.generate(pkg, intArrayOf(), flags.toLong(), 5, 6, emptySet(),
                     dummyUserState, 0, mockPkgSetting(pkg))
         }
 
@@ -329,7 +331,10 @@
             .ignored("Update for fixing b/128526493 and the testing is no longer valid")}
             enabled=${this.enabled}
             exported=${this.exported}
-            flags=${Integer.toBinaryString(this.flags)}
+            flags=${Integer.toBinaryString(
+                // Strip flag added in T
+                this.flags and (ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES.inv()))
+            }
             icon=${this.icon}
             labelRes=${this.labelRes}
             launchMode=${this.launchMode}
@@ -501,13 +506,22 @@
             receivers=${this.receivers?.joinToString { it.dumpToString() }
             .ignored("Checked separately in test")}
             reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
-            requestedPermissions=${this.requestedPermissions?.contentToString()}
+            requestedPermissions=${
+                // Strip compatibility permission added in T
+                this.requestedPermissions?.filter { x ->
+                    x != Manifest.permission.POST_NOTIFICATIONS
+                }?.ifEmpty { null }?.joinToString()
+            }
             requestedPermissionsFlags=${
-                this.requestedPermissionsFlags?.map {
+                // Strip the flag from compatibility permission added in T
+                this.requestedPermissionsFlags?.filterIndexed { index, _ ->
+                    index != ArrayUtils.indexOf(requestedPermissions,
+                                                Manifest.permission.POST_NOTIFICATIONS)
+                }?.map {
                     // Newer flags are stripped
                     it and (PackageInfo.REQUESTED_PERMISSION_REQUIRED
                             or PackageInfo.REQUESTED_PERMISSION_GRANTED)
-                }?.joinToString()
+                }?.ifEmpty { null }?.joinToString()
             }
             requiredAccountType=${this.requiredAccountType}
             requiredForAllUsers=${this.requiredForAllUsers}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index c4aa862..f530421 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -21,6 +21,7 @@
 import android.content.pm.parsing.ParsingPackage
 import android.content.pm.parsing.ParsingPackageUtils
 import android.content.pm.parsing.result.ParseResult
+import android.platform.test.annotations.Presubmit
 import androidx.test.InstrumentationRegistry
 import com.android.frameworks.servicestests.R
 import com.google.common.truth.Truth.assertThat
@@ -36,6 +37,7 @@
  *
  * This verifies these failures when the APK targets R.
  */
+@Presubmit
 class PackageParsingDeferErrorTest {
 
     companion object {
diff --git a/services/tests/servicestests/src/com/android/server/pm/permission/LegacyPermissionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/permission/LegacyPermissionManagerServiceTest.java
index 3261dfa..3551af8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/permission/LegacyPermissionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/permission/LegacyPermissionManagerServiceTest.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Process;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -41,6 +42,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class LegacyPermissionManagerServiceTest {
     private static final int SYSTEM_UID = 1000;
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
index 9d1c74b..a97ad8c 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
@@ -151,12 +151,12 @@
     }
 
     @Override
-    public void setRecordProviderStateChanges(boolean enabled) {
+    public void setRecordStateChangesForTests(boolean enabled) {
         failUnimplemented();
     }
 
     @Override
-    public boolean getRecordProviderStateChanges() {
+    public boolean getRecordStateChangesForTests() {
         return failUnimplemented();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java
index 97b8360..97095c4 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * A test support class used for tracking a piece of state in test objects like fakes and mocks.
@@ -79,6 +80,11 @@
         assertEquals(expectedCount, getChangeCount());
     }
 
+    /** Asserts the value has been {@link #set} to the expected values in the order given. */
+    public void assertChanges(T... expected) {
+        assertEquals(Arrays.asList(expected), mValues);
+    }
+
     /**
      * Returns the latest value passed to {@link #set}. If {@link #set} hasn't been called then the
      * initial value is returned.
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
index 20c25a0..d54e1f1 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
@@ -21,6 +21,14 @@
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_CERTAIN;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_DESTROYED;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_FAILED;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_INITIALIZING;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_PROVIDERS_INITIALIZING;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_STOPPED;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_UNCERTAIN;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProviderController.STATE_UNKNOWN;
 import static com.android.server.timezonedetector.location.TestSupport.USER1_CONFIG_GEO_DETECTION_DISABLED;
 import static com.android.server.timezonedetector.location.TestSupport.USER1_CONFIG_GEO_DETECTION_ENABLED;
 import static com.android.server.timezonedetector.location.TestSupport.USER2_CONFIG_GEO_DETECTION_ENABLED;
@@ -45,7 +53,9 @@
 import com.android.server.timezonedetector.ConfigurationInternal;
 import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
 import com.android.server.timezonedetector.TestState;
+import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
 import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
+import com.android.server.timezonedetector.location.LocationTimeZoneProviderController.State;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -73,6 +83,7 @@
             TimeZoneProviderEvent.createPermanentFailureEvent(ARBITRARY_TIME_MILLIS, "Test");
 
     private TestThreadingDomain mTestThreadingDomain;
+    private TestMetricsLogger mTestMetricsLogger;
     private TestCallback mTestCallback;
     private TestLocationTimeZoneProvider mTestPrimaryLocationTimeZoneProvider;
     private TestLocationTimeZoneProvider mTestSecondaryLocationTimeZoneProvider;
@@ -82,11 +93,12 @@
         // For simplicity, the TestThreadingDomain uses the test's main thread. To execute posted
         // runnables, the test must call methods on mTestThreadingDomain otherwise those runnables
         // will never get a chance to execute.
-        LocationTimeZoneProvider.ProviderMetricsLogger stubbedProviderMetricsLogger = stateEnum -> {
-            // Stubbed.
-        };
         mTestThreadingDomain = new TestThreadingDomain();
+        mTestMetricsLogger = new TestMetricsLogger();
+
         mTestCallback = new TestCallback(mTestThreadingDomain);
+
+        ProviderMetricsLogger stubbedProviderMetricsLogger = stateEnum -> {};
         mTestPrimaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
                 stubbedProviderMetricsLogger, mTestThreadingDomain, "primary");
         mTestSecondaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
@@ -94,10 +106,18 @@
     }
 
     @Test
+    public void controllerStartsInUnknownState() {
+        LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
+        assertControllerState(controller, STATE_UNKNOWN);
+    }
+
+    @Test
     public void initializationFailure_primary() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
         Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
@@ -112,10 +132,13 @@
         mTestPrimaryLocationTimeZoneProvider.assertInitialized();
         mTestSecondaryLocationTimeZoneProvider.assertInitialized();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -123,8 +146,8 @@
     @Test
     public void initializationFailure_secondary() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
         Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
@@ -139,10 +162,13 @@
         mTestPrimaryLocationTimeZoneProvider.assertInitialized();
         mTestSecondaryLocationTimeZoneProvider.assertInitialized();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -150,8 +176,8 @@
     @Test
     public void initializationFailure_both() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -165,8 +191,11 @@
         mTestPrimaryLocationTimeZoneProvider.assertInitialized();
         mTestSecondaryLocationTimeZoneProvider.assertInitialized();
 
+        assertControllerState(controller, STATE_FAILED);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING, STATE_FAILED);
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -174,8 +203,8 @@
     @Test
     public void initialState_started() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
         Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
@@ -188,10 +217,13 @@
         mTestPrimaryLocationTimeZoneProvider.assertInitialized();
         mTestSecondaryLocationTimeZoneProvider.assertInitialized();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -199,8 +231,8 @@
     @Test
     public void initialState_disabled() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_DISABLED);
 
@@ -211,8 +243,10 @@
         mTestPrimaryLocationTimeZoneProvider.assertInitialized();
         mTestSecondaryLocationTimeZoneProvider.assertInitialized();
 
+        assertControllerState(controller, STATE_STOPPED);
         mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -220,8 +254,8 @@
     @Test
     public void enabled_uncertaintySuggestionSentIfNoEventReceived() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -231,18 +265,22 @@
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Simulate time passing with no provider event being received from the primary.
         mTestThreadingDomain.executeNext();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         // The primary should have reported uncertainty, which should trigger the controller to
         // start the uncertainty timeout and start the secondary.
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -250,12 +288,14 @@
         // secondary.
         mTestThreadingDomain.executeNext();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         // Now both initialization timeouts should have triggered. The uncertainty timeout should
         // still not be triggered.
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -263,10 +303,12 @@
         // suggestion.
         mTestThreadingDomain.executeNext();
 
+        assertControllerState(controller, STATE_UNCERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_UNCERTAIN);
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -274,17 +316,20 @@
     @Test
     public void enabled_eventReceivedBeforeInitializationTimeout() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -293,9 +338,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -304,27 +351,32 @@
     @Test
     public void enabled_eventReceivedFromPrimaryAfterInitializationTimeout() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Simulate time passing with no provider event being received from the primary.
         mTestThreadingDomain.executeNext();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -333,9 +385,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -344,27 +398,32 @@
     @Test
     public void enabled_eventReceivedFromSecondaryAfterInitializationTimeout() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Simulate time passing with no provider event being received from the primary.
         mTestThreadingDomain.executeNext();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -373,10 +432,12 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -385,17 +446,20 @@
     @Test
     public void enabled_repeatedPrimaryCertainty() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -404,9 +468,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -415,9 +481,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -425,9 +493,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -436,27 +506,32 @@
     @Test
     public void enabled_repeatedSecondaryCertainty() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Simulate time passing with no provider event being received from the primary.
         mTestThreadingDomain.executeNext();
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -465,10 +540,12 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -477,10 +554,12 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -488,10 +567,12 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -500,17 +581,20 @@
     @Test
     public void enabled_uncertaintyTriggersASuggestionAfterUncertaintyTimeout() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -519,9 +603,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -532,10 +618,12 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -545,10 +633,12 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -559,10 +649,12 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -570,10 +662,12 @@
         // suggestion should be made.
         mTestThreadingDomain.executeNext();
 
+        assertControllerState(controller, STATE_UNCERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_UNCERTAIN);
         mTestCallback.assertUncertainSuggestionMadeFromEventAndCommit(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -582,17 +676,20 @@
     @Test
     public void enabled_briefUncertaintyTriggersNoSuggestion() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -601,9 +698,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -613,10 +712,12 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -626,9 +727,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -637,33 +740,39 @@
     @Test
     public void configChanges_enableAndDisableWithNoPreviousSuggestion() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_DISABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_STOPPED);
         mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Now signal a config change so that geo detection is enabled.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Now signal a config change so that geo detection is disabled.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
 
+        assertControllerState(controller, STATE_STOPPED);
         mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -671,25 +780,29 @@
     @Test
     public void configChanges_enableAndDisableWithPreviousSuggestion() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_DISABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_STOPPED);
         mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Now signal a config change so that geo detection is enabled.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -697,9 +810,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -710,8 +825,10 @@
         // of the time zone.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
 
+        assertControllerState(controller, STATE_STOPPED);
         mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_UNCERTAIN, STATE_STOPPED);
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -719,17 +836,20 @@
     @Test
     public void configChanges_userSwitch_enabledToEnabled() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -739,9 +859,11 @@
 
         // Receiving a "success" provider event should cause a suggestion to be made synchronously,
         // and also clear the scheduled uncertainty suggestion.
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -750,7 +872,7 @@
         testEnvironment.simulateConfigChange(USER2_CONFIG_GEO_DETECTION_ENABLED);
 
         // Confirm that the previous suggestion was overridden.
-        mTestCallback.assertUncertainSuggestionMadeAndCommit();
+        assertControllerState(controller, STATE_INITIALIZING);
 
         // We expect the provider to end up in PROVIDER_STATE_STARTED_INITIALIZING, but it should
         // have been stopped when the user changed.
@@ -760,23 +882,29 @@
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfig(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER2_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_UNCERTAIN, STATE_STOPPED, STATE_INITIALIZING);
+        mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
 
     @Test
     public void primaryPermFailure_secondaryEventsReceived() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -785,9 +913,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -795,9 +925,11 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -806,9 +938,11 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -817,9 +951,11 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
     }
@@ -827,17 +963,20 @@
     @Test
     public void primaryPermFailure_disableAndEnable() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -846,26 +985,32 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Now signal a config change so that geo detection is disabled.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
 
+        assertControllerState(controller, STATE_STOPPED);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
         // Now signal a config change so that geo detection is enabled.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -873,17 +1018,20 @@
     @Test
     public void secondaryPermFailure_primaryEventsReceived() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -893,10 +1041,12 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -904,9 +1054,11 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -915,9 +1067,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -926,9 +1080,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
     }
@@ -936,17 +1092,20 @@
     @Test
     public void secondaryPermFailure_disableAndEnable() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -956,10 +1115,12 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
@@ -967,17 +1128,21 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controller);
 
         // Now signal a config change so that geo detection is disabled.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
 
+        assertControllerState(controller, STATE_STOPPED);
         mTestPrimaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_STOPPED);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -985,9 +1150,11 @@
         // started.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -995,17 +1162,20 @@
     @Test
     public void bothPermFailure_disableAndEnable() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -1013,9 +1183,11 @@
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestMetricsLogger.assertStateChangesAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -1023,8 +1195,10 @@
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
 
+        assertControllerState(controller, STATE_FAILED);
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_FAILED);
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controller.isUncertaintyTimeoutSet());
     }
@@ -1033,8 +1207,8 @@
     public void stateRecording() {
         // The test provider enables state recording by default.
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, true /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -1043,12 +1217,15 @@
 
         {
             LocationTimeZoneManagerServiceState state = controller.getStateForTests();
+            assertEquals(STATE_INITIALIZING, state.getControllerState());
             assertNull(state.getLastSuggestion());
+            assertControllerRecordedStates(state,
+                    STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
             assertProviderStates(state.getPrimaryProviderStates(),
                     PROVIDER_STATE_STOPPED, PROVIDER_STATE_STARTED_INITIALIZING);
             assertProviderStates(state.getSecondaryProviderStates(), PROVIDER_STATE_STOPPED);
         }
-        controller.clearRecordedProviderStates();
+        controller.clearRecordedStates();
 
         // Simulate some provider behavior that will show up in the state recording.
 
@@ -1058,13 +1235,15 @@
 
         {
             LocationTimeZoneManagerServiceState state = controller.getStateForTests();
+            assertEquals(STATE_INITIALIZING, state.getControllerState());
             assertNull(state.getLastSuggestion());
+            assertControllerRecordedStates(state);
             assertProviderStates(
                     state.getPrimaryProviderStates(), PROVIDER_STATE_STARTED_UNCERTAIN);
             assertProviderStates(
                     state.getSecondaryProviderStates(), PROVIDER_STATE_STARTED_INITIALIZING);
         }
-        controller.clearRecordedProviderStates();
+        controller.clearRecordedStates();
 
         // Simulate a certain event from the secondary.
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
@@ -1072,18 +1251,22 @@
 
         {
             LocationTimeZoneManagerServiceState state = controller.getStateForTests();
+            assertEquals(STATE_CERTAIN, state.getControllerState());
             assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
                     state.getLastSuggestion().getZoneIds());
+            assertControllerRecordedStates(state, STATE_CERTAIN);
             assertProviderStates(state.getPrimaryProviderStates());
             assertProviderStates(
                     state.getSecondaryProviderStates(), PROVIDER_STATE_STARTED_CERTAIN);
         }
 
-        controller.clearRecordedProviderStates();
+        controller.clearRecordedStates();
         {
             LocationTimeZoneManagerServiceState state = controller.getStateForTests();
+            assertEquals(STATE_CERTAIN, state.getControllerState());
             assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
                     state.getLastSuggestion().getZoneIds());
+            assertControllerRecordedStates(state);
             assertProviderStates(state.getPrimaryProviderStates());
             assertProviderStates(state.getSecondaryProviderStates());
         }
@@ -1101,17 +1284,20 @@
     @Test
     public void destroy() {
         LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
-                mTestThreadingDomain, mTestPrimaryLocationTimeZoneProvider,
-                mTestSecondaryLocationTimeZoneProvider);
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controller, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         // Initialize and check initial state.
         controller.initialize(testEnvironment, mTestCallback);
 
+        assertControllerState(controller, STATE_INITIALIZING);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_PROVIDERS_INITIALIZING, STATE_STOPPED, STATE_INITIALIZING);
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controller.isUncertaintyTimeoutSet());
 
@@ -1121,9 +1307,11 @@
 
         // Receiving a "success" provider event should cause a suggestion to be made synchronously,
         // and also clear the scheduled uncertainty suggestion.
+        assertControllerState(controller, STATE_CERTAIN);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_CERTAIN);
         mTestCallback.assertCertainSuggestionMadeFromEventAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
         assertFalse(controller.isUncertaintyTimeoutSet());
@@ -1131,6 +1319,10 @@
         // Trigger destroy().
         controller.destroy();
 
+        assertControllerState(controller, STATE_DESTROYED);
+        mTestMetricsLogger.assertStateChangesAndCommit(
+                STATE_UNCERTAIN, STATE_STOPPED, STATE_DESTROYED);
+
         // Confirm that the previous suggestion was overridden.
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
 
@@ -1158,6 +1350,17 @@
                         .build());
     }
 
+    private static void assertControllerState(LocationTimeZoneProviderController controller,
+            @State String expectedState) {
+        assertEquals(expectedState, controller.getStateForTests().getControllerState());
+    }
+
+    private static void assertControllerRecordedStates(
+            LocationTimeZoneManagerServiceState state,
+            @State String... expectedStates) {
+        assertEquals(Arrays.asList(expectedStates), state.getControllerStates());
+    }
+
     private static class TestEnvironment extends LocationTimeZoneProviderController.Environment {
 
         // These timeouts are set deliberately so that:
@@ -1229,6 +1432,22 @@
         }
     }
 
+    private static class TestMetricsLogger
+            implements LocationTimeZoneProviderController.MetricsLogger {
+
+        private final TestState<@State String> mLatestStateEnum = new TestState<>();
+
+        @Override
+        public void onStateChange(@State String stateEnum) {
+            mLatestStateEnum.set(stateEnum);
+        }
+
+        public void assertStateChangesAndCommit(@State String... expectedStateEnums) {
+            mLatestStateEnum.assertChanges(expectedStateEnums);
+            mLatestStateEnum.commitLatest();
+        }
+    }
+
     private static class TestCallback extends LocationTimeZoneProviderController.Callback {
 
         private TestState<GeolocationTimeZoneSuggestion> mLatestSuggestion = new TestState<>();
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
index 3716507..7eb6c97 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
@@ -16,7 +16,7 @@
 
 package com.android.server.uri;
 
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -121,47 +121,47 @@
         LocalServices.addService(PackageManagerInternal.class, mPmInternal);
 
         for (int userId : new int[] { USER_PRIMARY, USER_SECONDARY }) {
-            when(mPmInternal.getPackageUid(eq(PKG_SOCIAL), anyInt(), eq(userId)))
+            when(mPmInternal.getPackageUid(eq(PKG_SOCIAL), anyLong(), eq(userId)))
                     .thenReturn(UserHandle.getUid(userId, UID_SOCIAL));
-            when(mPmInternal.getPackageUid(eq(PKG_CAMERA), anyInt(), eq(userId)))
+            when(mPmInternal.getPackageUid(eq(PKG_CAMERA), anyLong(), eq(userId)))
                     .thenReturn(UserHandle.getUid(userId, UID_CAMERA));
-            when(mPmInternal.getPackageUid(eq(PKG_PRIVATE), anyInt(), eq(userId)))
+            when(mPmInternal.getPackageUid(eq(PKG_PRIVATE), anyLong(), eq(userId)))
                     .thenReturn(UserHandle.getUid(userId, UID_PRIVATE));
-            when(mPmInternal.getPackageUid(eq(PKG_PUBLIC), anyInt(), eq(userId)))
+            when(mPmInternal.getPackageUid(eq(PKG_PUBLIC), anyLong(), eq(userId)))
                     .thenReturn(UserHandle.getUid(userId, UID_PUBLIC));
-            when(mPmInternal.getPackageUid(eq(PKG_FORCE), anyInt(), eq(userId)))
+            when(mPmInternal.getPackageUid(eq(PKG_FORCE), anyLong(), eq(userId)))
                     .thenReturn(UserHandle.getUid(userId, UID_FORCE));
-            when(mPmInternal.getPackageUid(eq(PKG_COMPLEX), anyInt(), eq(userId)))
+            when(mPmInternal.getPackageUid(eq(PKG_COMPLEX), anyLong(), eq(userId)))
                     .thenReturn(UserHandle.getUid(userId, UID_COMPLEX));
 
-            when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyLong(), eq(userId),
                     eq(Process.SYSTEM_UID)))
                     .thenReturn(buildCameraProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyLong(), eq(userId),
                     eq(UserHandle.getUid(userId, UID_CAMERA))))
                     .thenReturn(buildCameraProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyLong(), eq(userId),
                     eq(Process.SYSTEM_UID)))
                     .thenReturn(buildPrivateProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_PRIVATE), anyLong(), eq(userId),
                     eq(UserHandle.getUid(userId, UID_PRIVATE))))
                     .thenReturn(buildPrivateProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyLong(), eq(userId),
                     eq(Process.SYSTEM_UID)))
                     .thenReturn(buildPublicProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_PUBLIC), anyLong(), eq(userId),
                     eq(UserHandle.getUid(userId, UID_PUBLIC))))
                     .thenReturn(buildPublicProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyLong(), eq(userId),
                     eq(Process.SYSTEM_UID)))
                     .thenReturn(buildForceProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_FORCE), anyLong(), eq(userId),
                     eq(UserHandle.getUid(userId, UID_FORCE))))
                     .thenReturn(buildForceProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyLong(), eq(userId),
                     eq(Process.SYSTEM_UID)))
                     .thenReturn(buildComplexProvider(userId));
-            when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyInt(), eq(userId),
+            when(mPmInternal.resolveContentProvider(eq(PKG_COMPLEX), anyLong(), eq(userId),
                     eq(UserHandle.getUid(userId, UID_COMPLEX))))
                     .thenReturn(buildComplexProvider(userId));
         }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 9e46e1f..949ee01 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -63,6 +63,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -530,8 +531,8 @@
                     eq(UserHandle.getAppId(ai.uid)), eq(userIdForTest), anyLong()))
                     .thenReturn(idle[i]);
         }
-        when(mInjector.mPackageManagerInternal.getInstalledApplications(anyInt(), eq(userIdForTest),
-                anyInt())).thenReturn(installedApps);
+        when(mInjector.mPackageManagerInternal.getInstalledApplications(anyLong(),
+                eq(userIdForTest), anyInt())).thenReturn(installedApps);
         final int[] returnedIdleUids = controllerUnderTest.getIdleUidsForUser(userIdForTest);
 
         assertEquals(expectedIdleUids.length, returnedIdleUids.length);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 4eb9c06..c0f7596 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -126,15 +126,23 @@
             new VibrationAttributes.Builder().setUsage(
                     VibrationAttributes.USAGE_RINGTONE).build();
 
-    @Rule public MockitoRule rule = MockitoJUnit.rule();
-    @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+    @Rule
+    public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
-    @Mock private VibratorManagerService.NativeWrapper mNativeWrapperMock;
-    @Mock private PackageManagerInternal mPackageManagerInternalMock;
-    @Mock private PowerManagerInternal mPowerManagerInternalMock;
-    @Mock private PowerSaveState mPowerSaveStateMock;
-    @Mock private AppOpsManager mAppOpsManagerMock;
-    @Mock private IInputManager mIInputManagerMock;
+    @Mock
+    private VibratorManagerService.NativeWrapper mNativeWrapperMock;
+    @Mock
+    private PackageManagerInternal mPackageManagerInternalMock;
+    @Mock
+    private PowerManagerInternal mPowerManagerInternalMock;
+    @Mock
+    private PowerSaveState mPowerSaveStateMock;
+    @Mock
+    private AppOpsManager mAppOpsManagerMock;
+    @Mock
+    private IInputManager mIInputManagerMock;
 
     private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
 
@@ -397,6 +405,7 @@
     @Test
     public void registerVibratorStateListener_multipleVibratorsAreTriggered() throws Exception {
         mockVibrators(0, 1, 2);
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorManagerService service = createSystemReadyService();
         IVibratorStateListener[] listeners = new IVibratorStateListener[3];
         for (int i = 0; i < 3; i++) {
@@ -601,8 +610,8 @@
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
         AudioAttributes audioAttributes = new AudioAttributes.Builder()
                 .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY).build();
-        VibrationAttributes vibrationAttributes = new VibrationAttributes.Builder(
-                audioAttributes, effect).build();
+        VibrationAttributes vibrationAttributes =
+                new VibrationAttributes.Builder(audioAttributes).build();
 
         vibrate(service, effect, vibrationAttributes);
 
@@ -621,7 +630,7 @@
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 new VibrationAttributes.Builder().setUsage(
                         VibrationAttributes.USAGE_COMMUNICATION_REQUEST).build());
-        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK),
+        vibrate(service, VibrationEffect.createOneShot(2000, 200),
                 new VibrationAttributes.Builder().setUsage(
                         VibrationAttributes.USAGE_UNKNOWN).build());
 
@@ -642,6 +651,60 @@
     }
 
     @Test
+    public void vibrate_withAttributesUnknownUsage_usesEffectToIdentifyTouchUsage() {
+        VibratorManagerService service = createSystemReadyService();
+
+        VibrationAttributes unknownAttributes = VibrationAttributes.createForUsage(
+                VibrationAttributes.USAGE_UNKNOWN);
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), unknownAttributes);
+        vibrate(service, VibrationEffect.createOneShot(200, 200), unknownAttributes);
+        vibrate(service, VibrationEffect.createWaveform(
+                new long[] { 100, 200, 300 }, new int[] {1, 2, 3}, -1), unknownAttributes);
+        vibrate(service,
+                VibrationEffect.startComposition()
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL)
+                        .compose(),
+                unknownAttributes);
+
+        verify(mAppOpsManagerMock, times(4))
+                .checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+                        eq(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION), anyInt(), anyString());
+        verify(mAppOpsManagerMock, never())
+                .checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+                        eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
+    }
+
+    @Test
+    public void vibrate_withAttributesUnknownUsage_ignoresEffectIfNotHapticFeedbackCandidate() {
+        VibratorManagerService service = createSystemReadyService();
+
+        VibrationAttributes unknownAttributes = VibrationAttributes.createForUsage(
+                VibrationAttributes.USAGE_UNKNOWN);
+        vibrate(service, VibrationEffect.get(VibrationEffect.RINGTONES[0]), unknownAttributes);
+        vibrate(service, VibrationEffect.createOneShot(2000, 200), unknownAttributes);
+        vibrate(service, VibrationEffect.createWaveform(
+                new long[] { 100, 200, 300 }, new int[] {1, 2, 3}, 0), unknownAttributes);
+        vibrate(service,
+                VibrationEffect.startComposition()
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_THUD)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                        .compose(),
+                unknownAttributes);
+
+        verify(mAppOpsManagerMock, never())
+                .checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+                        eq(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION), anyInt(), anyString());
+        verify(mAppOpsManagerMock, times(4))
+                .checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+                        eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
+    }
+
+    @Test
     public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception {
         mockVibrators(1);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index cdb7230..2f054b00 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -809,7 +810,7 @@
                     service.isComponentEnabledForCurrentProfiles(
                             unapprovedAdditionalComponent));
             verify(mIpm, never()).getServiceInfo(
-                    eq(unapprovedAdditionalComponent), anyInt(), anyInt());
+                    eq(unapprovedAdditionalComponent), anyLong(), anyInt());
         }
     }
 
@@ -953,7 +954,7 @@
                     service.isComponentEnabledForCurrentProfiles(
                             unapprovedAdditionalComponent));
             verify(mIpm, never()).getServiceInfo(
-                    eq(unapprovedAdditionalComponent), anyInt(), anyInt());
+                    eq(unapprovedAdditionalComponent), anyLong(), anyInt());
         }
     }
 
@@ -1702,14 +1703,14 @@
                             assertTrue(service.isComponentEnabledForCurrentProfiles(
                                     componentName));
                             verify(mIpm, times(1)).getServiceInfo(
-                                    eq(componentName), anyInt(), anyInt());
+                                    eq(componentName), anyLong(), anyInt());
                         }
                     } else {
                         ComponentName componentName =
                                 ComponentName.unflattenFromString(packageOrComponent);
                         assertTrue(service.isComponentEnabledForCurrentProfiles(componentName));
                         verify(mIpm, times(1)).getServiceInfo(
-                                eq(componentName), anyInt(), anyInt());
+                                eq(componentName), anyLong(), anyInt());
                     }
                 }
             }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 622669a..837850f 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -397,7 +397,7 @@
         // MockPackageManager - default returns ApplicationInfo with matching calling UID
         mContext.setMockPackageManager(mPackageManagerClient);
 
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt()))
                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
                     Object[] args = invocation.getArguments();
                     return getApplicationInfo((String) args[0], mUid);
@@ -5043,7 +5043,7 @@
     public void testIsCallerInstantApp_primaryUser() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
 
         assertTrue(mService.isCallerInstantApp(45770, 0));
@@ -5056,8 +5056,8 @@
     public void testIsCallerInstantApp_secondaryUser() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info);
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
 
         assertTrue(mService.isCallerInstantApp(68638450, 10));
@@ -5067,7 +5067,7 @@
     public void testIsCallerInstantApp_userAllNotification() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(USER_SYSTEM)))
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(USER_SYSTEM)))
                 .thenReturn(info);
         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
 
@@ -5081,8 +5081,8 @@
     public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.uid = Binder.getCallingUid();
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info);
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null);
 
         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10);
 
@@ -5093,7 +5093,7 @@
     public void testResolveNotificationUid_sameApp() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.uid = Binder.getCallingUid();
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
 
         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
 
@@ -5104,7 +5104,7 @@
     public void testResolveNotificationUid_sameAppDiffPackage() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.uid = Binder.getCallingUid();
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info);
 
         int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0);
 
@@ -5115,7 +5115,7 @@
     public void testResolveNotificationUid_sameAppWrongUid() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.uid = 1356347;
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(info);
 
         try {
             mService.resolveNotificationUid("caller", "caller", 9, 0);
@@ -5154,7 +5154,7 @@
                 PackageManager.NameNotFoundException.class);
         ApplicationInfo ai = new ApplicationInfo();
         ai.uid = -1;
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(ai);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
 
         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
         try {
@@ -5174,7 +5174,7 @@
                 PackageManager.NameNotFoundException.class);
         ApplicationInfo ai = new ApplicationInfo();
         ai.uid = -1;
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(ai);
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai);
 
         // unlike the post case, ignore instead of throwing
         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index 29ef339..2e5cf3c 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -44,6 +44,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
@@ -307,7 +308,7 @@
         // MockPackageManager - default returns ApplicationInfo with matching calling UID
         mContext.setMockPackageManager(mPackageManagerClient);
 
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
+        when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt()))
                 .thenAnswer((Answer<ApplicationInfo>) invocation -> {
                     Object[] args = invocation.getArguments();
                     return getApplicationInfo((String) args[0], mUid);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 4cdae88..5800400 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -28,6 +28,7 @@
 
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
@@ -42,7 +43,6 @@
 import android.permission.IPermissionManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
-import android.util.Slog;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -169,7 +169,8 @@
 
         ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>(
                 ImmutableList.of(notThis, none, first, second));
-        when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS), anyInt())).thenReturn(infos);
+        when(mPackageManager.getInstalledPackages(eq((long) GET_PERMISSIONS), anyInt()))
+                .thenReturn(infos);
 
         Set<Pair<Integer, String>> actual = mPermissionHelper.getAppsRequestingPermission(0);
 
@@ -181,7 +182,7 @@
         int userId = 1;
         ParceledListSlice<PackageInfo> infos = ParceledListSlice.emptyList();
         when(mPackageManager.getPackagesHoldingPermissions(
-                eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyInt(), eq(userId)))
+                eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId)))
                 .thenReturn(infos);
         assertThat(mPermissionHelper.getAppsGrantedPermission(userId)).isNotNull();
     }
@@ -206,7 +207,7 @@
         ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>(
                 ImmutableList.of(first, second));
         when(mPackageManager.getPackagesHoldingPermissions(
-                eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyInt(), eq(userId)))
+                eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId)))
                 .thenReturn(infos);
 
         Set<Pair<Integer, String>> expected =
@@ -305,11 +306,11 @@
         ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>(
                 ImmutableList.of(first, second));
         when(mPackageManager.getPackagesHoldingPermissions(
-                eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyInt(), eq(userId)))
+                eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyLong(), eq(userId)))
                 .thenReturn(infos);
         ParceledListSlice<PackageInfo> requesting = new ParceledListSlice<>(
                 ImmutableList.of(first, second, third));
-        when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS), anyInt()))
+        when(mPackageManager.getInstalledPackages(eq((long) GET_PERMISSIONS), anyInt()))
                 .thenReturn(requesting);
 
         Map<Pair<Integer, String>, Boolean> expected = ImmutableMap.of(new Pair(1, "first"), true,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 0cab911..e2f0658f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -63,6 +63,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.notNull;
@@ -352,7 +353,7 @@
         doReturn(null).when(mMockPackageManager).getDefaultHomeActivity(anyInt());
         doReturn(mMockPackageManager).when(mAtm).getPackageManagerInternalLocked();
         doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
-        doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
+        doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(),
                 anyInt(), anyBoolean(), anyInt());
         doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
 
diff --git a/tests/AttestationVerificationTest/Android.bp b/tests/AttestationVerificationTest/Android.bp
new file mode 100644
index 0000000..a4741eed
--- /dev/null
+++ b/tests/AttestationVerificationTest/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2021 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 {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "AttestationVerificationTest",
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+    defaults: ["cts_defaults"],
+    manifest: "AndroidManifest.xml",
+    test_config: "AndroidTest.xml",
+    platform_apis: true,
+    certificate: "platform",
+    optimize: {
+        enabled: false,
+    },
+    test_suites: ["device-tests"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "platform-test-annotations",
+    ],
+}
diff --git a/tests/AttestationVerificationTest/AndroidManifest.xml b/tests/AttestationVerificationTest/AndroidManifest.xml
new file mode 100755
index 0000000..c42bde9
--- /dev/null
+++ b/tests/AttestationVerificationTest/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="android.security.attestationverification">
+
+    <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+    <uses-permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+
+    <application>
+        <uses-library android:name="android.test.runner"/>
+        <activity android:name=".SystemAttestationVerificationTest$TestActivity" />
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+         android:targetPackage="android.security.attestationverification">
+    </instrumentation>
+</manifest>
diff --git a/tests/AttestationVerificationTest/AndroidTest.xml b/tests/AttestationVerificationTest/AndroidTest.xml
new file mode 100644
index 0000000..1325760
--- /dev/null
+++ b/tests/AttestationVerificationTest/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<configuration description="Platform tests for Attestation Verification Framework">
+    <option name="test-tag" value="AttestationVerificationTest" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="AttestationVerificationTest.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.security.attestationverification" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt
new file mode 100644
index 0000000..48bfd6f
--- /dev/null
+++ b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt
@@ -0,0 +1,90 @@
+package android.security.attestationverification
+
+import android.os.Bundle
+import android.app.Activity
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import com.google.common.truth.Truth.assertThat
+import android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED
+import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY
+import android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN
+import java.lang.IllegalArgumentException
+import java.time.Duration
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+
+/** Test for system-defined attestation verifiers. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SystemAttestationVerificationTest {
+
+    @get:Rule
+    val rule = ActivityScenarioRule(TestActivity::class.java)
+
+    private lateinit var activity: Activity
+    private lateinit var avm: AttestationVerificationManager
+
+    @Before
+    fun setup() {
+        rule.getScenario().onActivity {
+            avm = it.getSystemService(AttestationVerificationManager::class.java)
+            activity = it
+        }
+    }
+
+    @Test
+    fun verifyAttestation_returnsUnknown() {
+        val future = CompletableFuture<Int>()
+        val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+        avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
+                activity.mainExecutor) { result, _ ->
+            future.complete(result)
+        }
+
+        assertThat(future.getSoon()).isEqualTo(RESULT_UNKNOWN)
+    }
+
+    @Test
+    fun verifyToken_returnsUnknown() {
+        val future = CompletableFuture<Int>()
+        val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+        avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
+                activity.mainExecutor) { _, token ->
+            val result = avm.verifyToken(profile, TYPE_PUBLIC_KEY, Bundle(), token, null)
+            future.complete(result)
+        }
+
+        assertThat(future.getSoon()).isEqualTo(RESULT_UNKNOWN)
+    }
+
+    @Test
+    fun verifyToken_tooBigMaxAgeThrows() {
+        val future = CompletableFuture<VerificationToken>()
+        val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+        avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
+                activity.mainExecutor) { _, token ->
+            future.complete(token)
+        }
+
+        assertThrows(IllegalArgumentException::class.java) {
+            avm.verifyToken(profile, TYPE_PUBLIC_KEY, Bundle(), future.getSoon(),
+                    Duration.ofSeconds(3601))
+        }
+    }
+
+    private fun <T> CompletableFuture<T>.getSoon(): T {
+        return this.get(1, TimeUnit.SECONDS)
+    }
+
+    class TestActivity : Activity() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+        }
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index cac7978..c18798f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -114,11 +114,16 @@
         flickerRule.checkFlakyAssertions()
     }
 
-    /** {@inheritDoc} */
+    /**
+     * Windows maybe recreated when rotated. Checks that the focus does not change or if it does,
+     * focus returns to [testApp]
+     */
     @FlakyTest(bugId = 190185577)
     @Test
-    override fun focusDoesNotChange() {
-        super.focusDoesNotChange()
+    fun focusChanges() {
+        testSpec.assertEventLog {
+            this.focusChanges(testApp.`package`)
+        }
     }
 
     /**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index ce2347d..d1bdeed 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -129,17 +129,6 @@
     open fun entireScreenCovered() = testSpec.entireScreenCovered()
 
     /**
-     * Checks that the focus doesn't change during animation
-     */
-    @Presubmit
-    @Test
-    open fun focusDoesNotChange() {
-        testSpec.assertEventLog {
-            this.focusDoesNotChange()
-        }
-    }
-
-    /**
      * Checks that [testApp] layer covers the entire screen at the start of the transition
      */
     @Presubmit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 3ca60e3..e44bee6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -146,15 +146,6 @@
         }
     }
 
-    /** {@inheritDoc} */
-    @Presubmit
-    @Test
-    override fun focusDoesNotChange() {
-        // This test doesn't work in shell transitions because of b/206101151
-        assumeFalse(isShellTransitionsEnabled)
-        super.focusDoesNotChange()
-    }
-
     /**
      * Checks that [testApp] layer covers the entire screen during the whole transition
      */
@@ -196,6 +187,19 @@
         }
     }
 
+    /**
+     * Checks that the focus doesn't change during animation
+     */
+    @Presubmit
+    @Test
+    fun focusDoesNotChange() {
+        // This test doesn't work in shell transitions because of b/206101151
+        assumeFalse(isShellTransitionsEnabled)
+        testSpec.assertEventLog {
+            this.focusDoesNotChange()
+        }
+    }
+
     /** {@inheritDoc} */
     @FlakyTest
     @Test
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
index 7ea2a62d..d4bc2a6 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
@@ -42,7 +42,7 @@
         swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
         frame.addView(swView);
         final RectsView hwBothView = new RectsView(this, 850, Color.GREEN);
-        // Don't actually need to render to a hw layer, but it's a good sanity-check that
+        // Don't actually need to render to a hw layer, but it's a good check that
         // we're rendering to/from layers correctly
         hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         frame.addView(hwBothView);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
index 7173a85..584ab59 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
@@ -42,7 +42,7 @@
         swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
         frame.addView(swView);
         final LinesView hwBothView = new LinesView(this, 850, Color.GREEN);
-        // Don't actually need to render to a hw layer, but it's a good sanity-check that
+        // Don't actually need to render to a hw layer, but it's a good check that
         // we're rendering to/from layers correctly
         hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         frame.addView(hwBothView);
diff --git a/tests/Internal/src/com/android/internal/util/ParcellingTests.java b/tests/Internal/src/com/android/internal/util/ParcellingTests.java
new file mode 100644
index 0000000..65a3436
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/util/ParcellingTests.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 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.internal.util;
+
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.Parcelling.BuiltIn.ForInstant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.time.Instant;
+
+/** Tests for {@link Parcelling}. */
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class ParcellingTests {
+
+    private Parcel mParcel = Parcel.obtain();
+
+    @Test
+    public void forInstant_normal() {
+        testForInstant(Instant.ofEpochSecond(500L, 10));
+    }
+
+    @Test
+    public void forInstant_minimum() {
+        testForInstant(Instant.MIN);
+    }
+
+    @Test
+    public void forInstant_maximum() {
+        testForInstant(Instant.MAX);
+    }
+
+    @Test
+    public void forInstant_null() {
+        testForInstant(null);
+    }
+
+    private void testForInstant(Instant instant) {
+        Parcelling<Instant> parcelling = new ForInstant();
+        parcelling.parcel(instant, mParcel, 0);
+        mParcel.setDataPosition(0);
+
+        Instant created = parcelling.unparcel(mParcel);
+
+        if (instant == null) {
+            assertNull(created);
+        } else {
+            assertEquals(instant, created);
+        }
+    }
+
+}