Merge "Implement new Layout manager APIs"
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 18ddffb..86e6183 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -330,7 +330,6 @@
      * @see JobScheduler#forNamespace(String)
      * @return The namespace this job was scheduled in. Will be {@code null} if there was no
      * explicit namespace set and this job is therefore in the default namespace.
-     * @hide
      */
     @Nullable
     public String getJobNamespace() {
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index 33668c7..4aec484 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -271,7 +271,6 @@
      * but will instead create or update the job inside the current namespace. A JobScheduler
      * instance dedicated to a namespace must be used to schedule or update jobs in that namespace.
      * @see #getNamespace()
-     * @hide
      */
     @NonNull
     public JobScheduler forNamespace(@NonNull String namespace) {
@@ -282,7 +281,6 @@
      * Get the namespace this JobScheduler instance is operating in. A {@code null} value means
      * that the app has not specified a namespace for this instance, and it is therefore using the
      * default namespace.
-     * @hide
      */
     @Nullable
     public String getNamespace() {
@@ -395,14 +393,21 @@
     public abstract void cancel(int jobId);
 
     /**
-     * Cancel <em>all</em> jobs that have been scheduled by the calling application.
+     * Cancel all jobs that have been scheduled in the current namespace by the
+     * calling application.
+     *
+     * <p>
+     * Starting with Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, this
+     * will only cancel within the current namespace. If a namespace hasn't been explicitly set
+     * with {@link #forNamespace(String)}, then this will cancel jobs in the default namespace.
+     * To cancel all jobs scheduled by the application,
+     * use {@link #cancelInAllNamespaces()} instead.
      */
     public abstract void cancelAll();
 
     /**
      * Cancel <em>all</em> jobs that have been scheduled by the calling application, regardless of
      * namespace.
-     * @hide
      */
     public void cancelInAllNamespaces() {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
@@ -424,7 +429,6 @@
      * If a namespace hasn't been explicitly set with {@link #forNamespace(String)},
      * then this will return jobs in the default namespace.
      * This includes jobs that are currently started as well as those that are still waiting to run.
-     * @hide
      */
     @NonNull
     public Map<String, List<JobInfo>> getPendingJobsInAllNamespaces() {
diff --git a/core/api/current.txt b/core/api/current.txt
index 0ad7d80..9a6e76b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -744,6 +744,7 @@
     field public static final int focusableInTouchMode = 16842971; // 0x10100db
     field public static final int focusedByDefault = 16844100; // 0x1010544
     field @Deprecated public static final int focusedMonthDateColor = 16843587; // 0x1010343
+    field public static final int focusedSearchResultHighlightColor;
     field public static final int font = 16844082; // 0x1010532
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
@@ -1355,6 +1356,7 @@
     field public static final int searchHintIcon = 16843988; // 0x10104d4
     field public static final int searchIcon = 16843907; // 0x1010483
     field public static final int searchMode = 16843221; // 0x10101d5
+    field public static final int searchResultHighlightColor;
     field public static final int searchSettingsDescription = 16843402; // 0x101028a
     field public static final int searchSuggestAuthority = 16843222; // 0x10101d6
     field public static final int searchSuggestIntentAction = 16843225; // 0x10101d9
@@ -8563,6 +8565,7 @@
     method public int getClipGrantFlags();
     method @NonNull public android.os.PersistableBundle getExtras();
     method public int getJobId();
+    method @Nullable public String getJobNamespace();
     method @Nullable public android.net.Network getNetwork();
     method public int getStopReason();
     method @NonNull public android.os.Bundle getTransientExtras();
@@ -8596,10 +8599,14 @@
     method public boolean canRunLongJobs();
     method public abstract void cancel(int);
     method public abstract void cancelAll();
+    method public void cancelInAllNamespaces();
     method public abstract int enqueue(@NonNull android.app.job.JobInfo, @NonNull android.app.job.JobWorkItem);
+    method @NonNull public android.app.job.JobScheduler forNamespace(@NonNull String);
     method @NonNull public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+    method @Nullable public String getNamespace();
     method @Nullable public abstract android.app.job.JobInfo getPendingJob(int);
     method public int getPendingJobReason(int);
+    method @NonNull public java.util.Map<java.lang.String,java.util.List<android.app.job.JobInfo>> getPendingJobsInAllNamespaces();
     method public abstract int schedule(@NonNull android.app.job.JobInfo);
     field public static final int PENDING_JOB_REASON_APP = 1; // 0x1
     field public static final int PENDING_JOB_REASON_APP_STANDBY = 2; // 0x2
@@ -11992,7 +11999,7 @@
     method @NonNull public int[] getChildSessionIds();
     method @NonNull public String[] getNames() throws java.io.IOException;
     method public int getParentSessionId();
-    method public boolean isKeepApplicationEnabledSetting();
+    method public boolean isApplicationEnabledSettingPersistent();
     method public boolean isMultiPackage();
     method public boolean isRequestUpdateOwnership();
     method public boolean isStaged();
@@ -12047,8 +12054,8 @@
     method @NonNull public android.os.UserHandle getUser();
     method public boolean hasParentSessionId();
     method public boolean isActive();
+    method public boolean isApplicationEnabledSettingPersistent();
     method public boolean isCommitted();
-    method public boolean isKeepApplicationEnabledSetting();
     method public boolean isMultiPackage();
     method public boolean isRequestUpdateOwnership();
     method public boolean isSealed();
@@ -12078,12 +12085,12 @@
     method public void setAppIcon(@Nullable android.graphics.Bitmap);
     method public void setAppLabel(@Nullable CharSequence);
     method public void setAppPackageName(@Nullable String);
+    method public void setApplicationEnabledSettingPersistent();
     method @Deprecated public void setAutoRevokePermissionsMode(boolean);
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
     method public void setInstallScenario(int);
     method public void setInstallerPackageName(@Nullable String);
-    method public void setKeepApplicationEnabledSetting();
     method public void setMultiPackage();
     method public void setOriginatingUid(int);
     method public void setOriginatingUri(@Nullable android.net.Uri);
@@ -12702,7 +12709,7 @@
     field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
     field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
-    field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
+    field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR, android.Manifest.permission.UWB_RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
     field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
     field @RequiresPermission(android.Manifest.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT) public static final int FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT = 4096; // 0x1000
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
@@ -28376,24 +28383,15 @@
 
   public final class NfcAdapter {
     method public void disableForegroundDispatch(android.app.Activity);
-    method @Deprecated public void disableForegroundNdefPush(android.app.Activity);
     method public void disableReaderMode(android.app.Activity);
     method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]);
-    method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
     method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
     method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
-    method @Deprecated public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
-    method @Deprecated public boolean isNdefPushEnabled();
     method public boolean isSecureNfcEnabled();
     method public boolean isSecureNfcSupported();
-    method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity);
-    method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
-    method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
-    method @Deprecated public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
-    method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
     field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
     field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
     field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
@@ -28425,18 +28423,6 @@
     field public static final int STATE_TURNING_ON = 2; // 0x2
   }
 
-  @Deprecated public static interface NfcAdapter.CreateBeamUrisCallback {
-    method @Deprecated public android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
-  }
-
-  @Deprecated public static interface NfcAdapter.CreateNdefMessageCallback {
-    method @Deprecated public android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
-  }
-
-  @Deprecated public static interface NfcAdapter.OnNdefPushCompleteCallback {
-    method @Deprecated public void onNdefPushComplete(android.nfc.NfcEvent);
-  }
-
   public static interface NfcAdapter.OnTagRemovedListener {
     method public void onTagRemoved();
   }
@@ -36410,7 +36396,6 @@
     field public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS = "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS";
     field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
     field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
-    field public static final String ACTION_MANAGE_APP_LONG_RUNNING_JOBS = "android.settings.MANAGE_APP_LONG_RUNNING_JOBS";
     field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
     field public static final String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
     field public static final String ACTION_MANAGE_SUPERVISOR_RESTRICTED_SETTING = "android.settings.MANAGE_SUPERVISOR_RESTRICTED_SETTING";
@@ -59274,6 +59259,7 @@
     method public void append(CharSequence, int, int);
     method public void beginBatchEdit();
     method public boolean bringPointIntoView(int);
+    method public boolean bringPointIntoView(@IntRange(from=0) int, boolean);
     method public void clearComposingText();
     method public void debug(int);
     method public boolean didTouchFocusSelect();
@@ -59311,6 +59297,8 @@
     method public int getExtendedPaddingTop();
     method public android.text.InputFilter[] getFilters();
     method public int getFirstBaselineToTopHeight();
+    method @ColorInt public int getFocusedSearchResultHighlightColor();
+    method public int getFocusedSearchResultIndex();
     method @Nullable public String getFontFeatureSettings();
     method @Nullable public String getFontVariationSettings();
     method public boolean getFreezesText();
@@ -59355,6 +59343,8 @@
     method public android.text.TextPaint getPaint();
     method public int getPaintFlags();
     method public String getPrivateImeOptions();
+    method @ColorInt public int getSearchResultHighlightColor();
+    method @Nullable public int[] getSearchResultHighlights();
     method public int getSelectionEnd();
     method public int getSelectionStart();
     method @ColorInt public int getShadowColor();
@@ -59439,6 +59429,8 @@
     method public void setFallbackLineSpacing(boolean);
     method public void setFilters(android.text.InputFilter[]);
     method public void setFirstBaselineToTopHeight(@IntRange(from=0) @Px int);
+    method public void setFocusedSearchResultHighlightColor(@ColorInt int);
+    method public void setFocusedSearchResultIndex(int);
     method public void setFontFeatureSettings(@Nullable String);
     method public boolean setFontVariationSettings(@Nullable String);
     method protected boolean setFrame(int, int, int, int);
@@ -59486,6 +59478,8 @@
     method public void setPrivateImeOptions(String);
     method public void setRawInputType(int);
     method public void setScroller(android.widget.Scroller);
+    method public void setSearchResultHighlightColor(@ColorInt int);
+    method public void setSearchResultHighlights(@Nullable int...);
     method public void setSelectAllOnFocus(boolean);
     method public void setShadowLayer(float, float, float, int);
     method public final void setShowSoftInputOnFocus(boolean);
@@ -59525,6 +59519,7 @@
     method public void setWidth(int);
     field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
     field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+    field public static final int FOCUSED_SEARCH_RESULT_INDEX_NONE = -1; // 0xffffffff
   }
 
   public enum TextView.BufferType {
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 1fa1e89..5c4fd10 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -252,6 +252,34 @@
 
 }
 
+package android.nfc {
+
+  public final class NfcAdapter {
+    method @Deprecated public void disableForegroundNdefPush(android.app.Activity);
+    method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
+    method @Deprecated public boolean invokeBeam(android.app.Activity);
+    method @Deprecated public boolean isNdefPushEnabled();
+    method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity);
+    method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
+    method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
+    method @Deprecated public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
+    method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
+  }
+
+  @Deprecated public static interface NfcAdapter.CreateBeamUrisCallback {
+    method public android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
+  }
+
+  @Deprecated public static interface NfcAdapter.CreateNdefMessageCallback {
+    method public android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
+  }
+
+  @Deprecated public static interface NfcAdapter.OnNdefPushCompleteCallback {
+    method public void onNdefPushComplete(android.nfc.NfcEvent);
+  }
+
+}
+
 package android.os {
 
   public class BatteryManager {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 85f8813..33ea8e1 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9668,18 +9668,14 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
-    method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
-    field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
   }
 
   public static interface NfcAdapter.ControllerAlwaysOnListener {
@@ -13845,6 +13841,7 @@
     method @Deprecated public boolean disableCellBroadcastRange(int, int, int);
     method @Deprecated public boolean enableCellBroadcastRange(int, int, int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPremiumSmsConsent(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.net.Uri getSmscIdentity();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public void resetAllCellBroadcastRanges();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPremiumSmsConsent(@NonNull String, int);
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 2c5acf1..1c10356 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -140,6 +140,17 @@
 
 }
 
+package android.nfc {
+
+  public final class NfcAdapter {
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
+    method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
+    field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
+  }
+
+}
+
 package android.os {
 
   public class Build {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 563f6d4..a14f3d3 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2489,7 +2489,7 @@
                 "RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO").setDefaultMode(
                 AppOpsManager.MODE_ALLOWED).build(),
         new AppOpInfo.Builder(OP_RUN_LONG_JOBS, OPSTR_RUN_LONG_JOBS, "RUN_LONG_JOBS")
-                .setPermission(Manifest.permission.RUN_LONG_JOBS).build(),
+                .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
             new AppOpInfo.Builder(OP_READ_MEDIA_VISUAL_USER_SELECTED,
                     OPSTR_READ_MEDIA_VISUAL_USER_SELECTED, "READ_MEDIA_VISUAL_USER_SELECTED")
                     .setPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index f0c39ab..c19a865 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -259,12 +259,15 @@
                 new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE)
             }, true),
             new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
+                new RegularPermission(Manifest.permission.BLUETOOTH_ADVERTISE),
                 new RegularPermission(Manifest.permission.BLUETOOTH_CONNECT),
+                new RegularPermission(Manifest.permission.BLUETOOTH_SCAN),
                 new RegularPermission(Manifest.permission.CHANGE_NETWORK_STATE),
                 new RegularPermission(Manifest.permission.CHANGE_WIFI_STATE),
                 new RegularPermission(Manifest.permission.CHANGE_WIFI_MULTICAST_STATE),
                 new RegularPermission(Manifest.permission.NFC),
                 new RegularPermission(Manifest.permission.TRANSMIT_IR),
+                new RegularPermission(Manifest.permission.UWB_RANGING),
                 new UsbDevicePermission(),
                 new UsbAccessoryPermission(),
             }, false)
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 9dd9c0f..9c1318e 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -64,7 +64,7 @@
 
     void requestUserPreapproval(in PackageInstaller.PreapprovalDetails details, in IntentSender statusReceiver);
 
-    boolean isKeepApplicationEnabledSetting();
+    boolean isApplicationEnabledSettingPersistent();
     boolean isRequestUpdateOwnership();
 
     ParcelFileDescriptor getAppMetadataFd();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index df1340d..0b74dd1 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2010,9 +2010,9 @@
          * @return {@code true} if this session will keep the existing application enabled setting
          * after installation.
          */
-        public boolean isKeepApplicationEnabledSetting() {
+        public boolean isApplicationEnabledSettingPersistent() {
             try {
-                return mSession.isKeepApplicationEnabledSetting();
+                return mSession.isApplicationEnabledSettingPersistent();
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -2265,7 +2265,7 @@
         /** {@hide} */
         public int requireUserAction = USER_ACTION_UNSPECIFIED;
         /** {@hide} */
-        public boolean keepApplicationEnabledSetting = false;
+        public boolean applicationEnabledSettingPersistent = false;
 
         /**
          * Construct parameters for a new package install session.
@@ -2310,7 +2310,7 @@
             rollbackDataPolicy = source.readInt();
             requireUserAction = source.readInt();
             packageSource = source.readInt();
-            keepApplicationEnabledSetting = source.readBoolean();
+            applicationEnabledSettingPersistent = source.readBoolean();
         }
 
         /** {@hide} */
@@ -2341,7 +2341,7 @@
             ret.rollbackDataPolicy = rollbackDataPolicy;
             ret.requireUserAction = requireUserAction;
             ret.packageSource = packageSource;
-            ret.keepApplicationEnabledSetting = keepApplicationEnabledSetting;
+            ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
             return ret;
         }
 
@@ -2839,8 +2839,8 @@
          * Request to keep the original application enabled setting. This will prevent the
          * application from being enabled if it was previously in a disabled state.
          */
-        public void setKeepApplicationEnabledSetting() {
-            this.keepApplicationEnabledSetting = true;
+        public void setApplicationEnabledSettingPersistent() {
+            this.applicationEnabledSettingPersistent = true;
         }
 
         /**
@@ -2895,7 +2895,8 @@
             pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
             pw.printPair("dataLoaderParams", dataLoaderParams);
             pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
-            pw.printPair("keepApplicationEnabledSetting", keepApplicationEnabledSetting);
+            pw.printPair("applicationEnabledSettingPersistent",
+                    applicationEnabledSettingPersistent);
             pw.println();
         }
 
@@ -2936,7 +2937,7 @@
             dest.writeInt(rollbackDataPolicy);
             dest.writeInt(requireUserAction);
             dest.writeInt(packageSource);
-            dest.writeBoolean(keepApplicationEnabledSetting);
+            dest.writeBoolean(applicationEnabledSettingPersistent);
         }
 
         public static final Parcelable.Creator<SessionParams>
@@ -3139,7 +3140,7 @@
         public boolean isPreapprovalRequested;
 
         /** @hide */
-        public boolean keepApplicationEnabledSetting;
+        public boolean applicationEnabledSettingPersistent;
 
         /** @hide */
         public int pendingUserActionReason;
@@ -3197,7 +3198,7 @@
             requireUserAction = source.readInt();
             installerUid = source.readInt();
             packageSource = source.readInt();
-            keepApplicationEnabledSetting = source.readBoolean();
+            applicationEnabledSettingPersistent = source.readBoolean();
             pendingUserActionReason = source.readInt();
         }
 
@@ -3732,8 +3733,8 @@
          * Returns {@code true} if this session will keep the existing application enabled setting
          * after installation.
          */
-        public boolean isKeepApplicationEnabledSetting() {
-            return keepApplicationEnabledSetting;
+        public boolean isApplicationEnabledSettingPersistent() {
+            return applicationEnabledSettingPersistent;
         }
 
         /**
@@ -3811,7 +3812,7 @@
             dest.writeInt(requireUserAction);
             dest.writeInt(installerUid);
             dest.writeInt(packageSource);
-            dest.writeBoolean(keepApplicationEnabledSetting);
+            dest.writeBoolean(applicationEnabledSettingPersistent);
             dest.writeInt(pendingUserActionReason);
         }
 
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 4e2acc0..0b503eb 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -214,12 +214,15 @@
      * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission
      * {@link android.Manifest.permission#FOREGROUND_SERVICE_CONNECTED_DEVICE} and one of the
      * following permissions:
+     * {@link android.Manifest.permission#BLUETOOTH_ADVERTISE},
      * {@link android.Manifest.permission#BLUETOOTH_CONNECT},
+     * {@link android.Manifest.permission#BLUETOOTH_SCAN},
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE},
      * {@link android.Manifest.permission#CHANGE_WIFI_STATE},
      * {@link android.Manifest.permission#CHANGE_WIFI_MULTICAST_STATE},
      * {@link android.Manifest.permission#NFC},
      * {@link android.Manifest.permission#TRANSMIT_IR},
+     * {@link android.Manifest.permission#UWB_RANGING},
      * or has been granted the access to one of the attached USB devices/accessories.
      */
     @RequiresPermission(
@@ -227,12 +230,15 @@
                 Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE,
             },
             anyOf = {
+                Manifest.permission.BLUETOOTH_ADVERTISE,
                 Manifest.permission.BLUETOOTH_CONNECT,
+                Manifest.permission.BLUETOOTH_SCAN,
                 Manifest.permission.CHANGE_NETWORK_STATE,
                 Manifest.permission.CHANGE_WIFI_STATE,
                 Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
                 Manifest.permission.NFC,
                 Manifest.permission.TRANSMIT_IR,
+                Manifest.permission.UWB_RANGING,
             },
             conditional = true
     )
diff --git a/core/java/android/nfc/BeamShareData.aidl b/core/java/android/nfc/BeamShareData.aidl
deleted file mode 100644
index a47e240..0000000
--- a/core/java/android/nfc/BeamShareData.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013 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.nfc;
-
-parcelable BeamShareData;
diff --git a/core/java/android/nfc/BeamShareData.java b/core/java/android/nfc/BeamShareData.java
deleted file mode 100644
index 6a40f98..0000000
--- a/core/java/android/nfc/BeamShareData.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package android.nfc;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.UserHandle;
-
-/**
- * Class to IPC data to be shared over Android Beam.
- * Allows bundling NdefMessage, Uris and flags in a single
- * IPC call. This is important as we want to reduce the
- * amount of IPC calls at "touch time".
- * @hide
- */
-public final class BeamShareData implements Parcelable {
-    public final NdefMessage ndefMessage;
-    public final Uri[] uris;
-    public final UserHandle userHandle;
-    public final int flags;
-
-    public BeamShareData(NdefMessage msg, Uri[] uris, UserHandle userHandle, int flags) {
-        this.ndefMessage = msg;
-        this.uris = uris;
-        this.userHandle = userHandle;
-        this.flags = flags;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        int urisLength = (uris != null) ? uris.length : 0;
-        dest.writeParcelable(ndefMessage, 0);
-        dest.writeInt(urisLength);
-        if (urisLength > 0) {
-            dest.writeTypedArray(uris, 0);
-        }
-        dest.writeParcelable(userHandle, 0);
-        dest.writeInt(this.flags);
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<BeamShareData> CREATOR =
-            new Parcelable.Creator<BeamShareData>() {
-        @Override
-        public BeamShareData createFromParcel(Parcel source) {
-            Uri[] uris = null;
-            NdefMessage msg = source.readParcelable(NdefMessage.class.getClassLoader(), android.nfc.NdefMessage.class);
-            int numUris = source.readInt();
-            if (numUris > 0) {
-                uris = new Uri[numUris];
-                source.readTypedArray(uris, Uri.CREATOR);
-            }
-            UserHandle userHandle = source.readParcelable(UserHandle.class.getClassLoader(), android.os.UserHandle.class);
-            int flags = source.readInt();
-
-            return new BeamShareData(msg, uris, userHandle, flags);
-        }
-
-        @Override
-        public BeamShareData[] newArray(int size) {
-            return new BeamShareData[size];
-        }
-    };
-}
diff --git a/core/java/android/nfc/IAppCallback.aidl b/core/java/android/nfc/IAppCallback.aidl
index 133146d..b06bf06 100644
--- a/core/java/android/nfc/IAppCallback.aidl
+++ b/core/java/android/nfc/IAppCallback.aidl
@@ -16,7 +16,6 @@
 
 package android.nfc;
 
-import android.nfc.BeamShareData;
 import android.nfc.Tag;
 
 /**
@@ -24,7 +23,5 @@
  */
 interface IAppCallback
 {
-    BeamShareData createBeamShareData(byte peerLlcpVersion);
-    oneway void onNdefPushComplete(byte peerLlcpVersion);
     oneway void onTagDiscovered(in Tag tag);
 }
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index de107a2..f6aa4b4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -18,7 +18,6 @@
 
 import android.app.PendingIntent;
 import android.content.IntentFilter;
-import android.nfc.BeamShareData;
 import android.nfc.NdefMessage;
 import android.nfc.Tag;
 import android.nfc.TechListParcel;
@@ -47,24 +46,18 @@
     int getState();
     boolean disable(boolean saveState);
     boolean enable();
-    boolean enableNdefPush();
-    boolean disableNdefPush();
-    boolean isNdefPushEnabled();
     void pausePolling(int timeoutInMs);
     void resumePolling();
 
     void setForegroundDispatch(in PendingIntent intent,
             in IntentFilter[] filters, in TechListParcel techLists);
     void setAppCallback(in IAppCallback callback);
-    oneway void invokeBeam();
-    oneway void invokeBeamInternal(in BeamShareData shareData);
 
     boolean ignore(int nativeHandle, int debounceMs, ITagRemovedCallback callback);
 
     void dispatch(in Tag tag);
 
     void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
-    void setP2pModes(int initatorModes, int targetModes);
 
     void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
     void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 911aaf3..8d75cac 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -19,9 +19,6 @@
 import android.app.Activity;
 import android.app.Application;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ContentProvider;
-import android.content.Intent;
-import android.net.Uri;
 import android.nfc.NfcAdapter.ReaderCallback;
 import android.os.Binder;
 import android.os.Bundle;
@@ -110,14 +107,8 @@
     class NfcActivityState {
         boolean resumed = false;
         Activity activity;
-        NdefMessage ndefMessage = null;  // static NDEF message
-        NfcAdapter.CreateNdefMessageCallback ndefMessageCallback = null;
-        NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback = null;
-        NfcAdapter.CreateBeamUrisCallback uriCallback = null;
-        Uri[] uris = null;
-        int flags = 0;
-        int readerModeFlags = 0;
         NfcAdapter.ReaderCallback readerCallback = null;
+        int readerModeFlags = 0;
         Bundle readerModeExtras = null;
         Binder token;
 
@@ -137,24 +128,16 @@
             unregisterApplication(activity.getApplication());
             resumed = false;
             activity = null;
-            ndefMessage = null;
-            ndefMessageCallback = null;
-            onNdefPushCompleteCallback = null;
-            uriCallback = null;
-            uris = null;
+            readerCallback = null;
             readerModeFlags = 0;
+            readerModeExtras = null;
             token = null;
         }
         @Override
         public String toString() {
-            StringBuilder s = new StringBuilder("[").append(" ");
-            s.append(ndefMessage).append(" ").append(ndefMessageCallback).append(" ");
-            s.append(uriCallback).append(" ");
-            if (uris != null) {
-                for (Uri uri : uris) {
-                    s.append(onNdefPushCompleteCallback).append(" ").append(uri).append("]");
-                }
-            }
+            StringBuilder s = new StringBuilder("[");
+            s.append(readerCallback);
+            s.append("]");
             return s.toString();
         }
     }
@@ -245,92 +228,6 @@
         }
     }
 
-    public void setNdefPushContentUri(Activity activity, Uri[] uris) {
-        boolean isResumed;
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = getActivityState(activity);
-            state.uris = uris;
-            isResumed = state.resumed;
-        }
-        if (isResumed) {
-            // requestNfcServiceCallback() verifies permission also
-            requestNfcServiceCallback();
-        } else {
-            // Crash API calls early in case NFC permission is missing
-            verifyNfcPermission();
-        }
-    }
-
-
-    public void setNdefPushContentUriCallback(Activity activity,
-            NfcAdapter.CreateBeamUrisCallback callback) {
-        boolean isResumed;
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = getActivityState(activity);
-            state.uriCallback = callback;
-            isResumed = state.resumed;
-        }
-        if (isResumed) {
-            // requestNfcServiceCallback() verifies permission also
-            requestNfcServiceCallback();
-        } else {
-            // Crash API calls early in case NFC permission is missing
-            verifyNfcPermission();
-        }
-    }
-
-    public void setNdefPushMessage(Activity activity, NdefMessage message, int flags) {
-        boolean isResumed;
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = getActivityState(activity);
-            state.ndefMessage = message;
-            state.flags = flags;
-            isResumed = state.resumed;
-        }
-        if (isResumed) {
-            // requestNfcServiceCallback() verifies permission also
-            requestNfcServiceCallback();
-        } else {
-            // Crash API calls early in case NFC permission is missing
-            verifyNfcPermission();
-        }
-    }
-
-    public void setNdefPushMessageCallback(Activity activity,
-            NfcAdapter.CreateNdefMessageCallback callback, int flags) {
-        boolean isResumed;
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = getActivityState(activity);
-            state.ndefMessageCallback = callback;
-            state.flags = flags;
-            isResumed = state.resumed;
-        }
-        if (isResumed) {
-            // requestNfcServiceCallback() verifies permission also
-            requestNfcServiceCallback();
-        } else {
-            // Crash API calls early in case NFC permission is missing
-            verifyNfcPermission();
-        }
-    }
-
-    public void setOnNdefPushCompleteCallback(Activity activity,
-            NfcAdapter.OnNdefPushCompleteCallback callback) {
-        boolean isResumed;
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = getActivityState(activity);
-            state.onNdefPushCompleteCallback = callback;
-            isResumed = state.resumed;
-        }
-        if (isResumed) {
-            // requestNfcServiceCallback() verifies permission also
-            requestNfcServiceCallback();
-        } else {
-            // Crash API calls early in case NFC permission is missing
-            verifyNfcPermission();
-        }
-    }
-
     /**
      * Request or unrequest NFC service callbacks.
      * Makes IPC call - do not hold lock.
@@ -351,86 +248,6 @@
         }
     }
 
-    /** Callback from NFC service, usually on binder thread */
-    @Override
-    public BeamShareData createBeamShareData(byte peerLlcpVersion) {
-        NfcAdapter.CreateNdefMessageCallback ndefCallback;
-        NfcAdapter.CreateBeamUrisCallback urisCallback;
-        NdefMessage message;
-        Activity activity;
-        Uri[] uris;
-        int flags;
-        NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = findResumedActivityState();
-            if (state == null) return null;
-
-            ndefCallback = state.ndefMessageCallback;
-            urisCallback = state.uriCallback;
-            message = state.ndefMessage;
-            uris = state.uris;
-            flags = state.flags;
-            activity = state.activity;
-        }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            // Make callbacks without lock
-            if (ndefCallback != null) {
-                message = ndefCallback.createNdefMessage(event);
-            }
-            if (urisCallback != null) {
-                uris = urisCallback.createBeamUris(event);
-                if (uris != null) {
-                    ArrayList<Uri> validUris = new ArrayList<Uri>();
-                    for (Uri uri : uris) {
-                        if (uri == null) {
-                            Log.e(TAG, "Uri not allowed to be null.");
-                            continue;
-                        }
-                        String scheme = uri.getScheme();
-                        if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
-                                !scheme.equalsIgnoreCase("content"))) {
-                            Log.e(TAG, "Uri needs to have " +
-                                    "either scheme file or scheme content");
-                            continue;
-                        }
-                        uri = ContentProvider.maybeAddUserId(uri, activity.getUserId());
-                        validUris.add(uri);
-                    }
-
-                    uris = validUris.toArray(new Uri[validUris.size()]);
-                }
-            }
-            if (uris != null && uris.length > 0) {
-                for (Uri uri : uris) {
-                    // Grant the NFC process permission to read these URIs
-                    activity.grantUriPermission("com.android.nfc", uri,
-                            Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-        return new BeamShareData(message, uris, activity.getUser(), flags);
-    }
-
-    /** Callback from NFC service, usually on binder thread */
-    @Override
-    public void onNdefPushComplete(byte peerLlcpVersion) {
-        NfcAdapter.OnNdefPushCompleteCallback callback;
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = findResumedActivityState();
-            if (state == null) return;
-
-            callback = state.onNdefPushCompleteCallback;
-        }
-        NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
-        // Make callback without lock
-        if (callback != null) {
-            callback.onNdefPushComplete(event);
-        }
-    }
-
     @Override
     public void onTagDiscovered(Tag tag) throws RemoteException {
         NfcAdapter.ReaderCallback callback;
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 0c7f529..c4b3c22 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -338,7 +338,10 @@
      */
     public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
 
-    /** @hide */
+    /**
+     * @hide
+     * @removed
+     */
     @SystemApi
     public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
 
@@ -374,7 +377,6 @@
     // Guarded by NfcAdapter.class
     static boolean sIsInitialized = false;
     static boolean sHasNfcFeature;
-    static boolean sHasBeamFeature;
 
     // Final after first constructor, except for
     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -438,7 +440,7 @@
      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
      * to another device.
      * @see #setOnNdefPushCompleteCallback
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -464,7 +466,7 @@
      * content currently visible to the user. Alternatively, you can call {@link
      * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
      * same data.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -494,7 +496,7 @@
 
 
      /**
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -526,26 +528,6 @@
     }
 
     /**
-     * Helper to check if this device has FEATURE_NFC_BEAM, but without using
-     * a context.
-     * Equivalent to
-     * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_BEAM)
-     */
-    private static boolean hasBeamFeature() {
-        IPackageManager pm = ActivityThread.getPackageManager();
-        if (pm == null) {
-            Log.e(TAG, "Cannot get package manager, assuming no Android Beam feature");
-            return false;
-        }
-        try {
-            return pm.hasSystemFeature(PackageManager.FEATURE_NFC_BEAM, 0);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Package manager query failed, assuming no Android Beam feature", e);
-            return false;
-        }
-    }
-
-    /**
      * Helper to check if this device has FEATURE_NFC, but without using
      * a context.
      * Equivalent to
@@ -624,7 +606,6 @@
     public static synchronized NfcAdapter getNfcAdapter(Context context) {
         if (!sIsInitialized) {
             sHasNfcFeature = hasNfcFeature();
-            sHasBeamFeature = hasBeamFeature();
             boolean hasHceFeature = hasNfcHceFeature();
             /* is this device meant to have NFC */
             if (!sHasNfcFeature && !hasHceFeature) {
@@ -1117,7 +1098,7 @@
      * @param uris an array of Uri(s) to push over Android Beam
      * @param activity activity for which the Uri(s) will be pushed
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -1126,26 +1107,7 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return;
-            }
         }
-        if (activity == null) {
-            throw new NullPointerException("activity cannot be null");
-        }
-        if (uris != null) {
-            for (Uri uri : uris) {
-                if (uri == null) throw new NullPointerException("Uri not " +
-                        "allowed to be null");
-                String scheme = uri.getScheme();
-                if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
-                        !scheme.equalsIgnoreCase("content"))) {
-                    throw new IllegalArgumentException("URI needs to have " +
-                            "either scheme file or scheme content");
-                }
-            }
-        }
-        mNfcActivityManager.setNdefPushContentUri(activity, uris);
     }
 
     /**
@@ -1205,7 +1167,7 @@
      * @param callback callback, or null to disable
      * @param activity activity for which the Uri(s) will be pushed
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -1214,14 +1176,7 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return;
-            }
         }
-        if (activity == null) {
-            throw new NullPointerException("activity cannot be null");
-        }
-        mNfcActivityManager.setNdefPushContentUriCallback(activity, callback);
     }
 
     /**
@@ -1295,7 +1250,7 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -1305,36 +1260,12 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return;
-            }
-        }
-        int targetSdkVersion = getSdkVersion();
-        try {
-            if (activity == null) {
-                throw new NullPointerException("activity cannot be null");
-            }
-            mNfcActivityManager.setNdefPushMessage(activity, message, 0);
-            for (Activity a : activities) {
-                if (a == null) {
-                    throw new NullPointerException("activities cannot contain null");
-                }
-                mNfcActivityManager.setNdefPushMessage(a, message, 0);
-            }
-        } catch (IllegalStateException e) {
-            if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
-                // Less strict on old applications - just log the error
-                Log.e(TAG, "Cannot call API with Activity that has already " +
-                        "been destroyed", e);
-            } else {
-                // Prevent new applications from making this mistake, re-throw
-                throw(e);
-            }
         }
     }
 
     /**
      * @hide
+     * @removed
      */
     @SystemApi
     public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
@@ -1343,10 +1274,6 @@
                 throw new UnsupportedOperationException();
             }
         }
-        if (activity == null) {
-            throw new NullPointerException("activity cannot be null");
-        }
-        mNfcActivityManager.setNdefPushMessage(activity, message, flags);
     }
 
     /**
@@ -1414,7 +1341,7 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -1424,44 +1351,7 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return;
-            }
         }
-        int targetSdkVersion = getSdkVersion();
-        try {
-            if (activity == null) {
-                throw new NullPointerException("activity cannot be null");
-            }
-            mNfcActivityManager.setNdefPushMessageCallback(activity, callback, 0);
-            for (Activity a : activities) {
-                if (a == null) {
-                    throw new NullPointerException("activities cannot contain null");
-                }
-                mNfcActivityManager.setNdefPushMessageCallback(a, callback, 0);
-            }
-        } catch (IllegalStateException e) {
-            if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
-                // Less strict on old applications - just log the error
-                Log.e(TAG, "Cannot call API with Activity that has already " +
-                        "been destroyed", e);
-            } else {
-                // Prevent new applications from making this mistake, re-throw
-                throw(e);
-            }
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
-            int flags) {
-        if (activity == null) {
-            throw new NullPointerException("activity cannot be null");
-        }
-        mNfcActivityManager.setNdefPushMessageCallback(activity, callback, flags);
     }
 
     /**
@@ -1501,7 +1391,7 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -1511,31 +1401,6 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return;
-            }
-        }
-        int targetSdkVersion = getSdkVersion();
-        try {
-            if (activity == null) {
-                throw new NullPointerException("activity cannot be null");
-            }
-            mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback);
-            for (Activity a : activities) {
-                if (a == null) {
-                    throw new NullPointerException("activities cannot contain null");
-                }
-                mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
-            }
-        } catch (IllegalStateException e) {
-            if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
-                // Less strict on old applications - just log the error
-                Log.e(TAG, "Cannot call API with Activity that has already " +
-                        "been destroyed", e);
-            } else {
-                // Prevent new applications from making this mistake, re-throw
-                throw(e);
-            }
         }
     }
 
@@ -1718,7 +1583,7 @@
      * @param activity the current foreground Activity that has registered data to share
      * @return whether the Beam animation was successfully invoked
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
@@ -1727,37 +1592,8 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return false;
-            }
         }
-        if (activity == null) {
-            throw new NullPointerException("activity may not be null.");
-        }
-        enforceResumed(activity);
-        try {
-            sService.invokeBeam();
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG, "invokeBeam: NFC process has died.");
-            attemptDeadServiceRecovery(e);
-            return false;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public boolean invokeBeam(BeamShareData shareData) {
-        try {
-            Log.e(TAG, "invokeBeamInternal()");
-            sService.invokeBeamInternal(shareData);
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG, "invokeBeam: NFC process has died.");
-            attemptDeadServiceRecovery(e);
-            return false;
-        }
+        return false;
     }
 
     /**
@@ -1783,9 +1619,9 @@
      *
      * @param activity foreground activity
      * @param message a NDEF Message to push over NFC
-     * @throws IllegalStateException if the activity is not currently in the foreground
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated use {@link #setNdefPushMessage} instead
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
+     * @removed this feature is removed. File sharing can work using other technology like
+     * Bluetooth.
      */
     @Deprecated
     public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
@@ -1793,15 +1629,7 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return;
-            }
         }
-        if (activity == null || message == null) {
-            throw new NullPointerException();
-        }
-        enforceResumed(activity);
-        mNfcActivityManager.setNdefPushMessage(activity, message, 0);
     }
 
     /**
@@ -1820,9 +1648,9 @@
      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
      *
      * @param activity the Foreground activity
-     * @throws IllegalStateException if the Activity has already been paused
-     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated use {@link #setNdefPushMessage} instead
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
+     * @removed this feature is removed. File sharing can work using other technology like
+     * Bluetooth.
      */
     @Deprecated
     public void disableForegroundNdefPush(Activity activity) {
@@ -1830,17 +1658,7 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return;
-            }
         }
-        if (activity == null) {
-            throw new NullPointerException();
-        }
-        enforceResumed(activity);
-        mNfcActivityManager.setNdefPushMessage(activity, null, 0);
-        mNfcActivityManager.setNdefPushMessageCallback(activity, null, 0);
-        mNfcActivityManager.setOnNdefPushCompleteCallback(activity, null);
     }
 
     /**
@@ -1965,40 +1783,24 @@
      * Enable NDEF Push feature.
      * <p>This API is for the Settings application.
      * @hide
+     * @removed
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     public boolean enableNdefPush() {
-        if (!sHasNfcFeature) {
-            throw new UnsupportedOperationException();
-        }
-        try {
-            return sService.enableNdefPush();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            return false;
-        }
+        return false;
     }
 
     /**
      * Disable NDEF Push feature.
      * <p>This API is for the Settings application.
      * @hide
+     * @removed
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     public boolean disableNdefPush() {
-        synchronized (NfcAdapter.class) {
-            if (!sHasNfcFeature) {
-                throw new UnsupportedOperationException();
-            }
-        }
-        try {
-            return sService.disableNdefPush();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            return false;
-        }
+        return false;
     }
 
     /**
@@ -2024,26 +1826,17 @@
      * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
      * @return true if NDEF Push feature is enabled
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * @removed this feature is removed. File sharing can work using other technology like
      * Bluetooth.
      */
     @java.lang.Deprecated
-
     public boolean isNdefPushEnabled() {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
-            if (!sHasBeamFeature) {
-                return false;
-            }
         }
-        try {
-            return sService.isNdefPushEnabled();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            return false;
-        }
+        return false;
     }
 
     /**
@@ -2134,17 +1927,6 @@
     }
 
     /**
-     * @hide
-     */
-    public void setP2pModes(int initiatorModes, int targetModes) {
-        try {
-            sService.setP2pModes(initiatorModes, targetModes);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-        }
-    }
-
-    /**
      * Registers a new NFC unlock handler with the NFC service.
      *
      * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 34aa7ef..547d406 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1142,6 +1142,16 @@
                 @BatteryConsumer.ProcessState int processState);
 
 
+
+        /**
+         * Returns the battery consumption (in microcoulombs) of UID's camera usage, derived from
+         * on-device power measurement data.
+         * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+         *
+         * {@hide}
+         */
+        public abstract long getCameraEnergyConsumptionUC();
+
         /**
          * Returns the battery consumption (in microcoulombs) used by this uid for each
          * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
@@ -2921,6 +2931,15 @@
     public abstract long getWifiEnergyConsumptionUC();
 
     /**
+     * Returns the battery consumption (in microcoulombs) of camera, derived from on
+     * device power measurement data.
+     * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+     *
+     * {@hide}
+     */
+    public abstract long getCameraEnergyConsumptionUC();
+
+    /**
      * Returns the battery consumption (in microcoulombs) that each
      * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
      * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}) consumed.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 249f486..32773a0 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -754,12 +754,9 @@
          * PackageManager.setComponentEnabledSetting} will now throw an
          * IllegalArgumentException if the given component class name does not
          * exist in the application's manifest.
-         * <li> {@link android.nfc.NfcAdapter#setNdefPushMessage
-         * NfcAdapter.setNdefPushMessage},
-         * {@link android.nfc.NfcAdapter#setNdefPushMessageCallback
-         * NfcAdapter.setNdefPushMessageCallback} and
-         * {@link android.nfc.NfcAdapter#setOnNdefPushCompleteCallback
-         * NfcAdapter.setOnNdefPushCompleteCallback} will throw
+         * <li> {@code NfcAdapter.setNdefPushMessage},
+         * {@code NfcAdapter.setNdefPushMessageCallback} and
+         * {@code NfcAdapter.setOnNdefPushCompleteCallback} will throw
          * IllegalStateException if called after the Activity has been destroyed.
          * <li> Accessibility services must require the new
          * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission or
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ec3ef9d..76ca20c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -603,6 +603,8 @@
      * Output: When a package data uri is passed as input, the activity result is set to
      * {@link android.app.Activity#RESULT_OK} if the permission was granted to the app. Otherwise,
      * the result is set to {@link android.app.Activity#RESULT_CANCELED}.
+     *
+     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MANAGE_APP_LONG_RUNNING_JOBS =
@@ -1692,7 +1694,6 @@
      * Input: Nothing.
      * <p>
      * Output: Nothing
-     * @see android.nfc.NfcAdapter#isNdefPushEnabled()
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_NFCSHARING_SETTINGS =
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4005bc8..d6c2d30 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -937,6 +937,13 @@
     private List<Path> mHighlightPaths;
     private List<Paint> mHighlightPaints;
     private Highlights mHighlights;
+    private int[] mSearchResultHighlights = null;
+    private Paint mSearchResultHighlightPaint = null;
+    private Paint mFocusedSearchResultHighlightPaint = null;
+    private int mFocusedSearchResultHighlightColor = 0xFFFF9632;
+    private int mSearchResultHighlightColor = 0xFFFFFF00;
+
+    private int mFocusedSearchResultIndex = -1;
     private int mGesturePreviewHighlightStart = -1;
     private int mGesturePreviewHighlightEnd = -1;
     private Paint mGesturePreviewHighlightPaint;
@@ -4030,6 +4037,8 @@
      */
     private static class TextAppearanceAttributes {
         int mTextColorHighlight = 0;
+        int mSearchResultHighlightColor = 0;
+        int mFocusedSearchResultHighlightColor = 0;
         ColorStateList mTextColor = null;
         ColorStateList mTextColorHint = null;
         ColorStateList mTextColorLink = null;
@@ -4062,6 +4071,9 @@
         public String toString() {
             return "TextAppearanceAttributes {\n"
                     + "    mTextColorHighlight:" + mTextColorHighlight + "\n"
+                    + "    mSearchResultHighlightColor: " + mSearchResultHighlightColor + "\n"
+                    + "    mFocusedSearchResultHighlightColor: "
+                    + mFocusedSearchResultHighlightColor + "\n"
                     + "    mTextColor:" + mTextColor + "\n"
                     + "    mTextColorHint:" + mTextColorHint + "\n"
                     + "    mTextColorLink:" + mTextColorLink + "\n"
@@ -4100,6 +4112,11 @@
     static {
         sAppearanceValues.put(com.android.internal.R.styleable.TextView_textColorHighlight,
                 com.android.internal.R.styleable.TextAppearance_textColorHighlight);
+        sAppearanceValues.put(com.android.internal.R.styleable.TextView_searchResultHighlightColor,
+                com.android.internal.R.styleable.TextAppearance_searchResultHighlightColor);
+        sAppearanceValues.put(
+                com.android.internal.R.styleable.TextView_focusedSearchResultHighlightColor,
+                com.android.internal.R.styleable.TextAppearance_focusedSearchResultHighlightColor);
         sAppearanceValues.put(com.android.internal.R.styleable.TextView_textColor,
                 com.android.internal.R.styleable.TextAppearance_textColor);
         sAppearanceValues.put(com.android.internal.R.styleable.TextView_textColorHint,
@@ -4174,6 +4191,16 @@
                     attributes.mTextColorHighlight =
                             appearance.getColor(attr, attributes.mTextColorHighlight);
                     break;
+                case com.android.internal.R.styleable.TextAppearance_searchResultHighlightColor:
+                    attributes.mSearchResultHighlightColor =
+                            appearance.getColor(attr, attributes.mSearchResultHighlightColor);
+                    break;
+                case com.android.internal.R.styleable
+                        .TextAppearance_focusedSearchResultHighlightColor:
+                    attributes.mFocusedSearchResultHighlightColor =
+                            appearance.getColor(attr,
+                                    attributes.mFocusedSearchResultHighlightColor);
+                    break;
                 case com.android.internal.R.styleable.TextAppearance_textColor:
                     attributes.mTextColor = appearance.getColorStateList(attr);
                     break;
@@ -4290,6 +4317,14 @@
             setHighlightColor(attributes.mTextColorHighlight);
         }
 
+        if (attributes.mSearchResultHighlightColor != 0) {
+            setSearchResultHighlightColor(attributes.mSearchResultHighlightColor);
+        }
+
+        if (attributes.mFocusedSearchResultHighlightColor != 0) {
+            setFocusedSearchResultHighlightColor(attributes.mFocusedSearchResultHighlightColor);
+        }
+
         if (attributes.mTextSize != -1) {
             mTextSizeUnit = attributes.mTextSizeUnit;
             setRawTextSize(attributes.mTextSize, true /* shouldRequestLayout */);
@@ -6176,6 +6211,238 @@
     }
 
     /**
+     * Sets the search result ranges with flatten range representation.
+     *
+     * Ranges are represented of flattened inclusive start and exclusive end integers array. The
+     * inclusive start offset of the {@code i}-th range is stored in {@code 2 * i}-th of the array.
+     * The exclusive end offset of the {@code i}-th range is stored in {@code 2* i + 1}-th of the
+     * array. For example, the two ranges: (1, 2) and (3, 4) are flattened into single int array
+     * [1, 2, 3, 4].
+     *
+     * TextView will render the search result with the highlights with specified color in the theme.
+     * If there is a focused search result, it is rendered with focused color. By calling this
+     * method, the focused search index will be cleared.
+     *
+     * @attr ref android.R.styleable#TextView_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor
+     *
+     * @see #getSearchResultHighlights()
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+     *
+     * @param ranges the flatten ranges of the search result. null for clear.
+     */
+    public void setSearchResultHighlights(@Nullable int... ranges) {
+        if (ranges == null) {
+            mSearchResultHighlights = null;
+            mHighlightPathsBogus = true;
+            return;
+        }
+        if (ranges.length % 2 == 1) {
+            throw new IllegalArgumentException(
+                    "Flatten ranges must have even numbered elements");
+        }
+        for (int j = 0; j < ranges.length / 2; ++j) {
+            int start = ranges[j * 2];
+            int end = ranges[j * 2 + 1];
+            if (start > end) {
+                throw new IllegalArgumentException(
+                        "Reverse range found in the flatten range: " + start + ", " + end + ""
+                                + " at " + j + "-th range");
+            }
+        }
+        mHighlightPathsBogus = true;
+        mSearchResultHighlights = ranges;
+        mFocusedSearchResultIndex = FOCUSED_SEARCH_RESULT_INDEX_NONE;
+        invalidate();
+    }
+
+    /**
+     * Gets the current search result ranges.
+     *
+     * @see #setSearchResultHighlights(int[])
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+     *
+     * @return a flatten search result ranges. null if not available.
+     */
+    @Nullable
+    public int[] getSearchResultHighlights() {
+        return mSearchResultHighlights;
+    }
+
+    /**
+     * A special index used for {@link #setFocusedSearchResultIndex(int)} and
+     * {@link #getFocusedSearchResultIndex()} inidicating there is no focused search result.
+     */
+    public static final int FOCUSED_SEARCH_RESULT_INDEX_NONE = -1;
+
+    /**
+     * Sets the focused search result index.
+     *
+     * The focused search result is drawn in a focused color.
+     * Calling {@link #FOCUSED_SEARCH_RESULT_INDEX_NONE} for clearing focused search result.
+     *
+     * This method must be called after setting search result ranges by
+     * {@link #setSearchResultHighlights(int[])}.
+     *
+     * @attr ref android.R.styleable#TextView_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor
+     *
+     * @see #setSearchResultHighlights(int[])
+     * @see #getSearchResultHighlights()
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+     *
+     * @param index a focused search index or {@link #FOCUSED_SEARCH_RESULT_INDEX_NONE}
+     */
+    public void setFocusedSearchResultIndex(int index) {
+        if (mSearchResultHighlights == null) {
+            throw new IllegalArgumentException("Search result range must be set beforehand.");
+        }
+        if (index < -1 || index >= mSearchResultHighlights.length / 2) {
+            throw new IllegalArgumentException("Focused index(" + index + ") must be larger than "
+                    + "-1 and less than range count(" + (mSearchResultHighlights.length / 2) + ")");
+        }
+        mFocusedSearchResultIndex = index;
+        mHighlightPathsBogus = true;
+        invalidate();
+    }
+
+    /**
+     * Gets the focused search result index.
+     *
+     * @attr ref android.R.styleable#TextView_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor
+     *
+     * @see #setSearchResultHighlights(int[])
+     * @see #getSearchResultHighlights()
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+
+     * @return a focused search index or {@link #FOCUSED_SEARCH_RESULT_INDEX_NONE}
+     */
+    public int getFocusedSearchResultIndex() {
+        return mFocusedSearchResultIndex;
+    }
+
+    /**
+     * Sets the search result highlight color.
+     *
+     * @attr ref android.R.styleable#TextView_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor
+     *
+     * @see #setSearchResultHighlights(int[])
+     * @see #getSearchResultHighlights()
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+
+     * @param color a search result highlight color.
+     */
+    public void setSearchResultHighlightColor(@ColorInt int color) {
+        mSearchResultHighlightColor = color;
+    }
+
+    /**
+     * Gets the search result highlight color.
+     *
+     * @attr ref android.R.styleable#TextView_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor
+     *
+     * @see #setSearchResultHighlights(int[])
+     * @see #getSearchResultHighlights()
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+
+     * @return a search result highlight color.
+     */
+    @ColorInt
+    public int getSearchResultHighlightColor() {
+        return mSearchResultHighlightColor;
+    }
+
+    /**
+     * Sets focused search result highlight color.
+     *
+     * @attr ref android.R.styleable#TextView_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor
+     *
+     * @see #setSearchResultHighlights(int[])
+     * @see #getSearchResultHighlights()
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+
+     * @param color a focused search result highlight color.
+     */
+    public void setFocusedSearchResultHighlightColor(@ColorInt int color) {
+        mFocusedSearchResultHighlightColor = color;
+    }
+
+    /**
+     * Gets focused search result highlight color.
+     *
+     * @attr ref android.R.styleable#TextView_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor
+     * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor
+     * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor
+     *
+     * @see #setSearchResultHighlights(int[])
+     * @see #getSearchResultHighlights()
+     * @see #setFocusedSearchResultIndex(int)
+     * @see #getFocusedSearchResultIndex()
+     * @see #setSearchResultHighlightColor(int)
+     * @see #getSearchResultHighlightColor()
+     * @see #setFocusedSearchResultHighlightColor(int)
+     * @see #getFocusedSearchResultHighlightColor()
+
+     * @return a focused search result highlight color.
+     */
+    @ColorInt
+    public int getFocusedSearchResultHighlightColor() {
+        return mFocusedSearchResultHighlightColor;
+    }
+
+    /**
      * Highlights the text range (from inclusive start offset to exclusive end offset) to show what
      * will be selected by the ongoing select handwriting gesture. While the gesture preview
      * highlight is shown, the selection or cursor is hidden. If the text or selection is changed,
@@ -8335,7 +8602,6 @@
             for (int i = 0; i < mHighlights.getSize(); ++i) {
                 final int[] ranges = mHighlights.getRanges(i);
                 final Paint paint = mHighlights.getPaint(i);
-
                 final Path path;
                 if (mPathRecyclePool.isEmpty()) {
                     path = new Path();
@@ -8363,6 +8629,8 @@
             }
         }
 
+        addSearchHighlightPaths();
+
         if (hasGesturePreviewHighlight()) {
             final Path path;
             if (mPathRecyclePool.isEmpty()) {
@@ -8381,6 +8649,67 @@
         mHighlightPathsBogus = false;
     }
 
+    private void addSearchHighlightPaths() {
+        if (mSearchResultHighlights != null) {
+            final Path searchResultPath;
+            if (mPathRecyclePool.isEmpty()) {
+                searchResultPath = new Path();
+            } else {
+                searchResultPath = mPathRecyclePool.get(mPathRecyclePool.size() - 1);
+                mPathRecyclePool.remove(mPathRecyclePool.size() - 1);
+                searchResultPath.reset();
+            }
+            final Path focusedSearchResultPath;
+            if (mFocusedSearchResultIndex == FOCUSED_SEARCH_RESULT_INDEX_NONE) {
+                focusedSearchResultPath = null;
+            } else if (mPathRecyclePool.isEmpty()) {
+                focusedSearchResultPath = new Path();
+            } else {
+                focusedSearchResultPath = mPathRecyclePool.get(mPathRecyclePool.size() - 1);
+                mPathRecyclePool.remove(mPathRecyclePool.size() - 1);
+                focusedSearchResultPath.reset();
+            }
+
+            boolean atLeastOnePathAdded = false;
+            for (int j = 0; j < mSearchResultHighlights.length / 2; ++j) {
+                final int start = mSearchResultHighlights[2 * j];
+                final int end = mSearchResultHighlights[2 * j + 1];
+                if (start < end) {
+                    if (j == mFocusedSearchResultIndex) {
+                        mLayout.getSelection(start, end, (left, top, right, bottom, layout) ->
+                                focusedSearchResultPath.addRect(left, top, right, bottom,
+                                        Path.Direction.CW)
+                        );
+                    } else {
+                        mLayout.getSelection(start, end, (left, top, right, bottom, layout) ->
+                                searchResultPath.addRect(left, top, right, bottom,
+                                        Path.Direction.CW)
+                        );
+                        atLeastOnePathAdded = true;
+                    }
+                }
+            }
+            if (atLeastOnePathAdded) {
+                if (mSearchResultHighlightPaint == null) {
+                    mSearchResultHighlightPaint = new Paint();
+                }
+                mSearchResultHighlightPaint.setColor(mSearchResultHighlightColor);
+                mSearchResultHighlightPaint.setStyle(Paint.Style.FILL);
+                mHighlightPaths.add(searchResultPath);
+                mHighlightPaints.add(mSearchResultHighlightPaint);
+            }
+            if (focusedSearchResultPath != null) {
+                if (mFocusedSearchResultHighlightPaint == null) {
+                    mFocusedSearchResultHighlightPaint = new Paint();
+                }
+                mFocusedSearchResultHighlightPaint.setColor(mFocusedSearchResultHighlightColor);
+                mFocusedSearchResultHighlightPaint.setStyle(Paint.Style.FILL);
+                mHighlightPaths.add(focusedSearchResultPath);
+                mHighlightPaints.add(mFocusedSearchResultHighlightPaint);
+            }
+        }
+    }
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private Path getUpdatedHighlightPath() {
         Path highlight = null;
@@ -10826,6 +11155,26 @@
      * This has to be called after layout. Returns true if anything changed.
      */
     public boolean bringPointIntoView(int offset) {
+        return bringPointIntoView(offset, false);
+    }
+
+    /**
+     * Move the insertion position of the given offset into visible area of the View.
+     *
+     * If the View is focused or {@code requestRectWithoutFocus} is set to true, this API may call
+     * {@link View#requestRectangleOnScreen(Rect)} to bring the point to the visible area if
+     * necessary.
+     *
+     * @param offset an offset of the character.
+     * @param requestRectWithoutFocus True for calling {@link View#requestRectangleOnScreen(Rect)}
+     *                                in the unfocused state. False for calling it only the View has
+     *                                the focus.
+     * @return true if anything changed, otherwise false.
+     *
+     * @see #bringPointIntoView(int)
+     */
+    public boolean bringPointIntoView(@IntRange(from = 0) int offset,
+            boolean requestRectWithoutFocus) {
         if (isLayoutRequested()) {
             mDeferScroll = offset;
             return false;
@@ -11002,7 +11351,7 @@
             changed = true;
         }
 
-        if (isFocused()) {
+        if (requestRectWithoutFocus && isFocused()) {
             // This offsets because getInterestingRect() is in terms of viewport coordinates, but
             // requestRectangleOnScreen() is in terms of content coordinates.
 
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 25ac1bd..600ae50 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -1279,10 +1279,15 @@
     public static float getBorderLuma(SurfaceControl surfaceControl, int w, int h) {
         final ScreenCapture.ScreenshotHardwareBuffer buffer =
                 ScreenCapture.captureLayers(surfaceControl, new Rect(0, 0, w, h), 1);
-        if (buffer != null) {
-            return getBorderLuma(buffer.getHardwareBuffer(), buffer.getColorSpace());
+        if (buffer == null) {
+            return 0;
         }
-        return 0;
+        final HardwareBuffer hwBuffer = buffer.getHardwareBuffer();
+        final float luma = getBorderLuma(hwBuffer, buffer.getColorSpace());
+        if (hwBuffer != null) {
+            hwBuffer.close();
+        }
+        return luma;
     }
 
     /** Returns the luminance in 0~1. */
diff --git a/core/java/com/android/internal/power/EnergyConsumerStats.java b/core/java/com/android/internal/power/EnergyConsumerStats.java
index 325df57..8cf17cda 100644
--- a/core/java/com/android/internal/power/EnergyConsumerStats.java
+++ b/core/java/com/android/internal/power/EnergyConsumerStats.java
@@ -58,7 +58,8 @@
     public static final int POWER_BUCKET_BLUETOOTH = 5;
     public static final int POWER_BUCKET_GNSS = 6;
     public static final int POWER_BUCKET_MOBILE_RADIO = 7;
-    public static final int NUMBER_STANDARD_POWER_BUCKETS = 8; // Buckets above this are custom.
+    public static final int POWER_BUCKET_CAMERA = 8;
+    public static final int NUMBER_STANDARD_POWER_BUCKETS = 9; // Buckets above this are custom.
 
     @IntDef(prefix = {"POWER_BUCKET_"}, value = {
             POWER_BUCKET_UNKNOWN,
@@ -70,6 +71,7 @@
             POWER_BUCKET_BLUETOOTH,
             POWER_BUCKET_GNSS,
             POWER_BUCKET_MOBILE_RADIO,
+            POWER_BUCKET_CAMERA,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface StandardPowerBucket {
diff --git a/core/proto/android/nfc/nfc_service.proto b/core/proto/android/nfc/nfc_service.proto
index 2df1d5d..1dcd5cc 100644
--- a/core/proto/android/nfc/nfc_service.proto
+++ b/core/proto/android/nfc/nfc_service.proto
@@ -60,7 +60,7 @@
     optional bool secure_nfc_capable = 13;
     optional bool vr_mode_enabled = 14;
     optional DiscoveryParamsProto discovery_params = 15;
-    optional P2pLinkManagerProto p2p_link_manager = 16;
+    reserved 16;
     optional com.android.nfc.cardemulation.CardEmulationManagerProto card_emulation_manager = 17;
     optional NfcDispatcherProto nfc_dispatcher = 18;
     optional string native_crash_logs = 19 [(.android.privacy).dest = DEST_EXPLICIT];
@@ -77,38 +77,6 @@
     optional bool enable_p2p = 5;
 }
 
-// Debugging information for com.android.nfc.P2pLinkManager
-message P2pLinkManagerProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    enum LinkState {
-        LINK_STATE_UNKNOWN = 0;
-        LINK_STATE_DOWN = 1;
-        LINK_STATE_DEBOUNCE = 2;
-        LINK_STATE_UP = 3;
-    }
-
-    enum SendState {
-        SEND_STATE_UNKNOWN = 0;
-        SEND_STATE_NOTHING_TO_SEND = 1;
-        SEND_STATE_NEED_CONFIRMATION = 2;
-        SEND_STATE_SENDING = 3;
-        SEND_STATE_COMPLETE = 4;
-        SEND_STATE_CANCELED = 5;
-    }
-
-    optional int32 default_miu = 1;
-    optional int32 default_rw_size = 2;
-    optional LinkState link_state = 3;
-    optional SendState send_state = 4;
-    optional int32 send_flags = 5;
-    optional bool send_enabled = 6;
-    optional bool receive_enabled = 7;
-    optional string callback_ndef = 8 [(.android.privacy).dest = DEST_EXPLICIT];
-    optional .android.nfc.NdefMessageProto message_to_send = 9;
-    repeated string uris_to_send = 10 [(.android.privacy).dest = DEST_EXPLICIT];
-}
-
 // Debugging information for com.android.nfc.NfcDispatcher
 message NfcDispatcherProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
index 35aae8f..5a18d9e 100644
--- a/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
+++ b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
@@ -31,7 +31,7 @@
     optional string cur_focused_window_soft_input_mode = 6;
     optional .android.view.inputmethod.EditorInfoProto cur_attribute = 7;
     optional string cur_id = 8;
-    optional bool show_requested = 9;
+    reserved 9; // deprecated show_requested
     optional bool show_explicitly_requested = 10;
     optional bool show_forced = 11;
     optional bool input_shown = 12;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 81b3af0..c43221d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6994,14 +6994,12 @@
     <permission android:name="android.permission.MANAGE_WEARABLE_SENSING_SERVICE"
                 android:protectionLevel="signature|privileged" />
 
-    <!-- Allows applications to use the long running jobs APIs.
-         <p>This is a special access permission that can be revoked by the system or the user.
-         <p>Apps need to target API {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above
-         to be able to request this permission.
-         <p>Protection level: appop
+    <!-- Allows applications to use the long running jobs APIs. For more details
+         see {@link android.app.job.JobInfo.Builder#setUserInitiated}.
+         <p>Protection level: normal
      -->
     <permission android:name="android.permission.RUN_LONG_JOBS"
-                android:protectionLevel="normal|appop"/>
+                android:protectionLevel="normal"/>
 
     <!-- Allows an app access to the installer provided app metadata.
         @SystemApi
@@ -7578,7 +7576,7 @@
             </intent-filter>
         </service>
 
-        <service android:name="com.android.server.art.BackgroundDexOptJobService"
+        <service android:name="com.android.server.art.BackgroundDexoptJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f4d563c..1b6f88f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5138,6 +5138,15 @@
         <attr name="textLocale" format="string" />
         <!-- Color of the text selection highlight. -->
         <attr name="textColorHighlight" />
+        <!-- Color of search results highlight.
+             This color is typically used when TextView/EditText shows search result in-app text
+             search invoked with Ctrl+F. -->
+        <attr name="searchResultHighlightColor" format="color" />
+        <!-- Color of focused search result highlight.
+             This color is typically used when TextView/EditText shows search result in-app text
+             search invoked with Ctrl+F. -->
+        <attr name="focusedSearchResultHighlightColor" format="color" />
+
         <!-- Color of the hint text. -->
         <attr name="textColorHint" />
         <!-- Color of the links. -->
@@ -5215,6 +5224,14 @@
         <attr name="textColor" />
         <!-- Color of the text selection highlight. -->
         <attr name="textColorHighlight" />
+        <!-- Color of search results highlight.
+             This color is typically used when TextView/EditText shows search result in-app text
+             search invoked with Ctrl+F. -->
+        <attr name="searchResultHighlightColor" format="color" />
+        <!-- Color of focused search result highlight.
+             This color is typically used when TextView/EditText shows search result in-app text
+             search invoked with Ctrl+F. -->
+        <attr name="focusedSearchResultHighlightColor" format="color" />
         <!-- Color of the hint text. -->
         <attr name="textColorHint" />
         <!-- Base text color, typeface, size, and style. -->
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 6047738..f4b49e6 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -126,6 +126,8 @@
     <public name="keyboardLayoutType" />
     <public name="allowUpdateOwnership" />
     <public name="isCredential"/>
+    <public name="searchResultHighlightColor" />
+    <public name="focusedSearchResultHighlightColor" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01cd0000">
diff --git a/core/tests/BroadcastRadioTests/AndroidManifest.xml b/core/tests/BroadcastRadioTests/AndroidManifest.xml
index 869b484..8f655ef 100644
--- a/core/tests/BroadcastRadioTests/AndroidManifest.xml
+++ b/core/tests/BroadcastRadioTests/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.hardware.radio.tests">
+    package="com.android.frameworks.broadcastradiotests">
 
     <uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
 
@@ -25,7 +25,7 @@
 
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="android.hardware.radio.tests"
+        android:targetPackage="com.android.frameworks.broadcastradiotests"
         android:label="Tests for Broadcast Radio APIs" >
     </instrumentation>
 </manifest>
diff --git a/core/tests/BroadcastRadioTests/AndroidTest.xml b/core/tests/BroadcastRadioTests/AndroidTest.xml
index ed88537..b7e93cd 100644
--- a/core/tests/BroadcastRadioTests/AndroidTest.xml
+++ b/core/tests/BroadcastRadioTests/AndroidTest.xml
@@ -25,7 +25,7 @@
     <option name="test-tag" value="BroadcastRadioTests" />
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.hardware.radio.tests" />
+        <option name="package" value="com.android.frameworks.broadcastradiotests" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/DefaultRadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/DefaultRadioTunerTest.java
similarity index 90%
rename from core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/DefaultRadioTunerTest.java
rename to core/tests/BroadcastRadioTests/src/android/hardware/radio/DefaultRadioTunerTest.java
index 65e55a2..63de759 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/DefaultRadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/DefaultRadioTunerTest.java
@@ -14,17 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.tests.unittests;
+package android.hardware.radio;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
 
 import android.graphics.Bitmap;
-import android.hardware.radio.ProgramList;
-import android.hardware.radio.ProgramSelector;
-import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioTuner;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -167,9 +163,7 @@
     @Test
     public void setConfigFlag_forRadioTuner_throwsException() {
         UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
-                () -> {
-            DEFAULT_RADIO_TUNER.setConfigFlag(/* flag= */ 1, /* value= */ false);
-        });
+                () -> DEFAULT_RADIO_TUNER.setConfigFlag(/* flag= */ 1, /* value= */ false));
 
         assertWithMessage("Exception for setting config flag on default radio tuner")
                 .that(thrown).hasMessageThat().contains("Setting config flag is not supported");
@@ -178,9 +172,7 @@
     @Test
     public void setParameters_forRadioTuner_throwsException() {
         UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
-                () -> {
-            DEFAULT_RADIO_TUNER.setParameters(Map.of("testKey", "testValue"));
-        });
+                () -> DEFAULT_RADIO_TUNER.setParameters(Map.of("testKey", "testValue")));
 
         assertWithMessage("Exception for setting parameters from default radio tuner")
                 .that(thrown).hasMessageThat().contains("Setting parameters is not supported");
@@ -189,9 +181,7 @@
     @Test
     public void getParameters_forRadioTuner_throwsException() {
         UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
-                () -> {
-            DEFAULT_RADIO_TUNER.getParameters(List.of("testKey"));
-        });
+                () -> DEFAULT_RADIO_TUNER.getParameters(List.of("testKey")));
 
         assertWithMessage("Exception for getting parameters from default radio tuner")
                 .that(thrown).hasMessageThat().contains("Getting parameters is not supported");
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramListTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
similarity index 97%
rename from core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramListTest.java
rename to core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
index 9a999e4..f807bad 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramListTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.tests.unittests;
+package android.hardware.radio;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -29,14 +29,6 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
-import android.hardware.radio.IRadioService;
-import android.hardware.radio.ITuner;
-import android.hardware.radio.ITunerCallback;
-import android.hardware.radio.ProgramList;
-import android.hardware.radio.ProgramSelector;
-import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioMetadata;
-import android.hardware.radio.RadioTuner;
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.util.ArraySet;
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramSelectorTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramSelectorTest.java
similarity index 99%
rename from core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramSelectorTest.java
rename to core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramSelectorTest.java
index 9399907..ae43a1c 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramSelectorTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramSelectorTest.java
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.tests.unittests;
+package android.hardware.radio;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
 
 import android.annotation.Nullable;
-import android.hardware.radio.ProgramSelector;
-import android.hardware.radio.RadioManager;
 import android.os.Parcel;
 
 import org.junit.Test;
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioAnnouncementTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioAnnouncementTest.java
similarity index 96%
rename from core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioAnnouncementTest.java
rename to core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioAnnouncementTest.java
index 6e1bb4b4..b0fb26a 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioAnnouncementTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioAnnouncementTest.java
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.tests.unittests;
+package android.hardware.radio;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
 
-import android.hardware.radio.Announcement;
-import android.hardware.radio.ProgramSelector;
 import android.os.Parcel;
 import android.util.ArrayMap;
 
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
similarity index 98%
rename from core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java
rename to core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
index afbf8c3..79a6b0d 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.tests.unittests;
+package android.hardware.radio;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -30,14 +30,6 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.hardware.radio.Announcement;
-import android.hardware.radio.IAnnouncementListener;
-import android.hardware.radio.ICloseHandle;
-import android.hardware.radio.IRadioService;
-import android.hardware.radio.ProgramSelector;
-import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioMetadata;
-import android.hardware.radio.RadioTuner;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.RemoteException;
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioMetadataTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
similarity index 98%
rename from core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioMetadataTest.java
rename to core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
index 5771135..e348a51 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioMetadataTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.tests.unittests;
+package android.hardware.radio;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
 
 import android.graphics.Bitmap;
-import android.hardware.radio.RadioMetadata;
 import android.os.Parcel;
 
 import org.junit.Test;
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
similarity index 98%
rename from core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/TunerAdapterTest.java
rename to core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
index c8b4493..487086c 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/TunerAdapterTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.tests.unittests;
+package android.hardware.radio;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -32,13 +32,6 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.graphics.Bitmap;
-import android.hardware.radio.IRadioService;
-import android.hardware.radio.ITuner;
-import android.hardware.radio.ITunerCallback;
-import android.hardware.radio.ProgramSelector;
-import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioMetadata;
-import android.hardware.radio.RadioTuner;
 import android.os.Build;
 import android.os.RemoteException;
 
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
deleted file mode 100644
index cabeb13..0000000
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright (C) 2017 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.hardware.radio.tests.functional;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.atMost;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.testng.Assert.assertThrows;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.radio.ProgramSelector;
-import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioTuner;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A test for broadcast radio API.
- */
-@RunWith(MockitoJUnitRunner.class)
-public class RadioTunerTest {
-    private static final String TAG = "BroadcastRadioTests.RadioTuner";
-
-    public final Context mContext = InstrumentationRegistry.getContext();
-
-    private final int kConfigCallbackTimeoutMs = 10000;
-    private final int kCancelTimeoutMs = 1000;
-    private final int kTuneCallbackTimeoutMs = 30000;
-    private final int kFullScanTimeoutMs = 60000;
-
-    private RadioManager mRadioManager;
-    private RadioTuner mRadioTuner;
-    private RadioManager.ModuleProperties mModule;
-    private final List<RadioManager.ModuleProperties> mModules = new ArrayList<>();
-    @Mock private RadioTuner.Callback mCallback;
-
-    RadioManager.AmBandDescriptor mAmBandDescriptor;
-    RadioManager.FmBandDescriptor mFmBandDescriptor;
-
-    RadioManager.BandConfig mAmBandConfig;
-    RadioManager.BandConfig mFmBandConfig;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-
-        // check if radio is supported and skip the test if it's not
-        PackageManager packageManager = mContext.getPackageManager();
-        boolean isRadioSupported = packageManager.hasSystemFeature(
-                PackageManager.FEATURE_BROADCAST_RADIO);
-        assumeTrue(isRadioSupported);
-
-        // Check radio access permission
-        int res = mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_BROADCAST_RADIO);
-        assertEquals("ACCESS_BROADCAST_RADIO permission not granted",
-                PackageManager.PERMISSION_GRANTED, res);
-
-        mRadioManager = (RadioManager)mContext.getSystemService(Context.RADIO_SERVICE);
-        assertNotNull(mRadioManager);
-
-        int status = mRadioManager.listModules(mModules);
-        assertEquals(RadioManager.STATUS_OK, status);
-        assertFalse(mModules.isEmpty());
-    }
-
-    @After
-    public void tearDown() {
-        mRadioManager = null;
-        mModules.clear();
-        if (mRadioTuner != null) {
-            mRadioTuner.close();
-            mRadioTuner = null;
-        }
-        resetCallback();
-    }
-
-    private void openTuner() {
-        openTuner(true);
-    }
-
-    private void resetCallback() {
-        verify(mCallback, never()).onError(anyInt());
-        verify(mCallback, never()).onTuneFailed(anyInt(), any());
-        verify(mCallback, never()).onControlChanged(anyBoolean());
-        Mockito.reset(mCallback);
-    }
-
-    private void openTuner(boolean withAudio) {
-        assertNull(mRadioTuner);
-
-        // find FM band and build its config
-        mModule = mModules.get(0);
-
-        for (RadioManager.BandDescriptor band : mModule.getBands()) {
-            Log.d(TAG, "Band: " + band);
-            int bandType = band.getType();
-            if (bandType == RadioManager.BAND_AM || bandType == RadioManager.BAND_AM_HD) {
-                mAmBandDescriptor = (RadioManager.AmBandDescriptor)band;
-            }
-            if (bandType == RadioManager.BAND_FM || bandType == RadioManager.BAND_FM_HD) {
-                mFmBandDescriptor = (RadioManager.FmBandDescriptor)band;
-            }
-        }
-        assertNotNull(mAmBandDescriptor);
-        assertNotNull(mFmBandDescriptor);
-        mAmBandConfig = new RadioManager.AmBandConfig.Builder(mAmBandDescriptor).build();
-        mFmBandConfig = new RadioManager.FmBandConfig.Builder(mFmBandDescriptor).build();
-
-        mRadioTuner = mRadioManager.openTuner(mModule.getId(),
-                mFmBandConfig, withAudio, mCallback, null);
-        if (!withAudio) {
-            // non-audio sessions might not be supported - if so, then skip the test
-            assumeNotNull(mRadioTuner);
-        }
-        assertNotNull(mRadioTuner);
-        verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any());
-        resetCallback();
-
-        boolean isAntennaConnected = mRadioTuner.isAntennaConnected();
-        assertTrue(isAntennaConnected);
-    }
-
-    @Test
-    public void testOpenTuner() {
-        openTuner();
-    }
-
-    @Test
-    public void testReopenTuner() throws Throwable {
-        openTuner();
-        mRadioTuner.close();
-        mRadioTuner = null;
-        Thread.sleep(100);  // TODO(b/36122635): force reopen
-        openTuner();
-    }
-
-    @Test
-    public void testDoubleClose() {
-        openTuner();
-        mRadioTuner.close();
-        mRadioTuner.close();
-    }
-
-    @Test
-    public void testUseAfterClose() {
-        openTuner();
-        mRadioTuner.close();
-        int ret = mRadioTuner.cancel();
-        assertEquals(RadioManager.STATUS_INVALID_OPERATION, ret);
-    }
-
-    @Test
-    public void testSetAndGetConfiguration() {
-        openTuner();
-
-        // set
-        int ret = mRadioTuner.setConfiguration(mAmBandConfig);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any());
-
-        // get
-        RadioManager.BandConfig[] config = new RadioManager.BandConfig[1];
-        ret = mRadioTuner.getConfiguration(config);
-        assertEquals(RadioManager.STATUS_OK, ret);
-
-        assertEquals(mAmBandConfig, config[0]);
-    }
-
-    @Test
-    public void testSetBadConfiguration() throws Throwable {
-        openTuner();
-
-        // set null config
-        int ret = mRadioTuner.setConfiguration(null);
-        assertEquals(RadioManager.STATUS_BAD_VALUE, ret);
-        verify(mCallback, never()).onConfigurationChanged(any());
-
-        // setting good config should recover
-        ret = mRadioTuner.setConfiguration(mAmBandConfig);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any());
-    }
-
-    @Test
-    public void testMute() {
-        openTuner();
-
-        boolean isMuted = mRadioTuner.getMute();
-        assertFalse(isMuted);
-
-        int ret = mRadioTuner.setMute(true);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        isMuted = mRadioTuner.getMute();
-        assertTrue(isMuted);
-
-        ret = mRadioTuner.setMute(false);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        isMuted = mRadioTuner.getMute();
-        assertFalse(isMuted);
-    }
-
-    @Test
-    public void testMuteNoAudio() {
-        openTuner(false);
-
-        int ret = mRadioTuner.setMute(false);
-        assertEquals(RadioManager.STATUS_ERROR, ret);
-
-        boolean isMuted = mRadioTuner.getMute();
-        assertTrue(isMuted);
-    }
-
-    @Test
-    public void testStep() {
-        openTuner();
-
-        int ret = mRadioTuner.step(RadioTuner.DIRECTION_DOWN, true);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(any());
-
-        resetCallback();
-
-        ret = mRadioTuner.step(RadioTuner.DIRECTION_UP, false);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(any());
-    }
-
-    @Test
-    public void testStepLoop() {
-        openTuner();
-
-        for (int i = 0; i < 10; i++) {
-            Log.d(TAG, "step loop iteration " + (i + 1));
-
-            int ret = mRadioTuner.step(RadioTuner.DIRECTION_DOWN, true);
-            assertEquals(RadioManager.STATUS_OK, ret);
-            verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(any());
-
-            resetCallback();
-        }
-    }
-
-    @Test
-    public void testTuneAndGetPI() {
-        openTuner();
-
-        int channel = mFmBandConfig.getLowerLimit() + mFmBandConfig.getSpacing();
-
-        // test tune
-        int ret = mRadioTuner.tune(channel, 0);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        ArgumentCaptor<RadioManager.ProgramInfo> infoc =
-                ArgumentCaptor.forClass(RadioManager.ProgramInfo.class);
-        verify(mCallback, timeout(kTuneCallbackTimeoutMs))
-                .onProgramInfoChanged(infoc.capture());
-        assertEquals(channel, infoc.getValue().getChannel());
-
-        // test getProgramInformation
-        RadioManager.ProgramInfo[] info = new RadioManager.ProgramInfo[1];
-        ret = mRadioTuner.getProgramInformation(info);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        assertNotNull(info[0]);
-        assertEquals(channel, info[0].getChannel());
-        Log.d(TAG, "PI: " + info[0].toString());
-    }
-
-    @Test
-    public void testDummyCancel() {
-        openTuner();
-
-        int ret = mRadioTuner.cancel();
-        assertEquals(RadioManager.STATUS_OK, ret);
-    }
-
-    @Test
-    public void testLateCancel() {
-        openTuner();
-
-        int ret = mRadioTuner.step(RadioTuner.DIRECTION_DOWN, false);
-        assertEquals(RadioManager.STATUS_OK, ret);
-        verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(any());
-
-        int cancelRet = mRadioTuner.cancel();
-        assertEquals(RadioManager.STATUS_OK, cancelRet);
-    }
-
-    @Test
-    public void testScanAndCancel() {
-        openTuner();
-
-        /* There is a possible race condition between scan and cancel commands - the scan may finish
-         * before cancel command is issued. Thus we accept both outcomes in this test.
-         */
-        int scanRet = mRadioTuner.scan(RadioTuner.DIRECTION_DOWN, true);
-        int cancelRet = mRadioTuner.cancel();
-
-        assertEquals(RadioManager.STATUS_OK, scanRet);
-        assertEquals(RadioManager.STATUS_OK, cancelRet);
-
-        verify(mCallback, after(kCancelTimeoutMs).atMost(1))
-                .onTuneFailed(eq(RadioTuner.TUNER_RESULT_CANCELED), any());
-        verify(mCallback, atMost(1)).onProgramInfoChanged(any());
-        Mockito.reset(mCallback);
-    }
-
-    @Test
-    public void testStartBackgroundScan() {
-        openTuner();
-
-        boolean ret = mRadioTuner.startBackgroundScan();
-        boolean isSupported = mModule.isBackgroundScanningSupported();
-        assertEquals(isSupported, ret);
-    }
-
-    @Test
-    public void testGetProgramList() {
-        openTuner();
-
-        try {
-            Map<String, String> filter = new HashMap<>();
-            filter.put("com.google.dummy", "dummy");
-            List<RadioManager.ProgramInfo> list = mRadioTuner.getProgramList(filter);
-            assertNotNull(list);
-        } catch (IllegalStateException e) {
-            // the list may or may not be ready at this point
-            Log.i(TAG, "Background list is not ready");
-        }
-    }
-
-    @Test
-    public void testTuneFromProgramList() {
-        openTuner();
-
-        List<RadioManager.ProgramInfo> list;
-
-        try {
-            list = mRadioTuner.getProgramList(null);
-            assertNotNull(list);
-        } catch (IllegalStateException e) {
-            Log.i(TAG, "Background list is not ready, trying to fix it");
-
-            boolean success = mRadioTuner.startBackgroundScan();
-            assertTrue(success);
-            verify(mCallback, timeout(kFullScanTimeoutMs)).onBackgroundScanComplete();
-
-            list = mRadioTuner.getProgramList(null);
-            assertNotNull(list);
-        }
-
-        if (list.isEmpty()) {
-            Log.i(TAG, "Program list is empty, can't test tune");
-            return;
-        }
-
-        ProgramSelector sel = list.get(0).getSelector();
-        mRadioTuner.tune(sel);
-        ArgumentCaptor<RadioManager.ProgramInfo> infoc =
-                ArgumentCaptor.forClass(RadioManager.ProgramInfo.class);
-        verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(infoc.capture());
-        assertEquals(sel, infoc.getValue().getSelector());
-    }
-
-    @Test
-    public void testForcedAnalog() {
-        openTuner();
-
-        boolean isSupported = true;
-        boolean isForced;
-        try {
-            isForced = mRadioTuner.isAnalogForced();
-            assertFalse(isForced);
-        } catch (IllegalStateException ex) {
-            Log.i(TAG, "Forced analog switch is not supported by this tuner");
-            isSupported = false;
-        }
-
-        if (isSupported) {
-            mRadioTuner.setAnalogForced(true);
-            isForced = mRadioTuner.isAnalogForced();
-            assertTrue(isForced);
-
-            mRadioTuner.setAnalogForced(false);
-            isForced = mRadioTuner.isAnalogForced();
-            assertFalse(isForced);
-        } else {
-            assertThrows(IllegalStateException.class, () -> mRadioTuner.setAnalogForced(true));
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index cd61dbb..f6d67d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -47,7 +47,7 @@
 
     private final @NonNull PipBoundsState mPipBoundsState;
     private final PipSnapAlgorithm mSnapAlgorithm;
-    private final PipKeepClearAlgorithm mPipKeepClearAlgorithm;
+    private final PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
 
     private float mDefaultSizePercent;
     private float mMinAspectRatioForMinSize;
@@ -62,7 +62,7 @@
 
     public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
             @NonNull PipSnapAlgorithm pipSnapAlgorithm,
-            @NonNull PipKeepClearAlgorithm pipKeepClearAlgorithm) {
+            @NonNull PipKeepClearAlgorithmInterface pipKeepClearAlgorithm) {
         mPipBoundsState = pipBoundsState;
         mSnapAlgorithm = pipSnapAlgorithm;
         mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithmInterface.java
similarity index 97%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithmInterface.java
index e3495e1..5045cf9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithmInterface.java
@@ -24,7 +24,7 @@
  * Interface for interacting with keep clear algorithm used to move PiP window out of the way of
  * keep clear areas.
  */
-public interface PipKeepClearAlgorithm {
+public interface PipKeepClearAlgorithmInterface {
 
     /**
      * Adjust the position of picture in picture window based on the registered keep clear areas.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
index 690505e..ed8dc7de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -26,14 +26,14 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipKeepClearAlgorithm;
+import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
 
 import java.util.Set;
 
 /**
  * Calculates the adjusted position that does not occlude keep clear areas.
  */
-public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithm {
+public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithmInterface {
 
     private boolean mKeepClearAreaGravityEnabled =
             SystemProperties.getBoolean(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 3153313..e83854e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -46,8 +46,6 @@
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.util.Pair;
 import android.util.Size;
 import android.view.DisplayInfo;
@@ -85,7 +83,7 @@
 import com.android.wm.shell.pip.PipAppOpsListener;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipKeepClearAlgorithm;
+import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
 import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
@@ -137,7 +135,7 @@
     private PipAppOpsListener mAppOpsListener;
     private PipMediaController mMediaController;
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
-    private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
+    private PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
     private PipBoundsState mPipBoundsState;
     private PipMotionHelper mPipMotionHelper;
     private PipTouchHandler mTouchHandler;
@@ -380,7 +378,7 @@
             PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
-            PipKeepClearAlgorithm pipKeepClearAlgorithm,
+            PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
             PipBoundsState pipBoundsState,
             PipMotionHelper pipMotionHelper,
             PipMediaController pipMediaController,
@@ -419,7 +417,7 @@
             PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
-            PipKeepClearAlgorithm pipKeepClearAlgorithm,
+            PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
             @NonNull PipBoundsState pipBoundsState,
             PipMotionHelper pipMotionHelper,
             PipMediaController pipMediaController,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 31490e4..b042063 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -37,7 +37,7 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.pip.PipKeepClearAlgorithm;
+import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -62,7 +62,7 @@
             @NonNull TvPipBoundsState tvPipBoundsState,
             @NonNull PipSnapAlgorithm pipSnapAlgorithm) {
         super(context, tvPipBoundsState, pipSnapAlgorithm,
-                new PipKeepClearAlgorithm() {
+                new PipKeepClearAlgorithmInterface() {
                 });
         this.mTvPipBoundsState = tvPipBoundsState;
         this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 66d0a2a..665267f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -170,6 +170,7 @@
                 if (!isCustomRotate()) {
                     mStartLuma = TransitionAnimation.getBorderLuma(hardwareBuffer, colorSpace);
                 }
+                hardwareBuffer.close();
             }
 
             t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 94a16da..02d50f4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.app.Activity
+import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerBuilder
@@ -28,6 +29,7 @@
 import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
 import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
+import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -163,10 +165,25 @@
     @Presubmit
     @Test
     fun pipAppLayerCoversFullScreenOnStart() {
+        Assume.assumeFalse(tapl.isTablet)
         flicker.assertLayersStart { visibleRegion(pipApp).coversExactly(startingBounds) }
     }
 
     /**
+     * Checks that the visible region of [pipApp] covers the full display area at the start of the
+     * transition
+     */
+    @Postsubmit
+    @Test
+    fun pipAppLayerPlusLetterboxCoversFullScreenOnStartTablet() {
+        Assume.assumeFalse(tapl.isTablet)
+        flicker.assertLayersStart {
+            visibleRegion(pipApp.or(ComponentNameMatcher.LETTERBOX))
+                .coversExactly(startingBounds)
+        }
+    }
+
+    /**
      * Checks that the visible region of [testApp] plus the visible region of [pipApp] cover the
      * full display area at the end of the transition
      */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index 262e429..298d0a6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -64,7 +64,7 @@
         initializeMockResources();
         mPipBoundsState = new PipBoundsState(mContext);
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
-                new PipSnapAlgorithm(), new PipKeepClearAlgorithm() {});
+                new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {});
 
         mPipBoundsState.setDisplayLayout(
                 new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 9088077..17e7d74 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -98,7 +98,7 @@
         mPipBoundsState = new PipBoundsState(mContext);
         mPipTransitionState = new PipTransitionState();
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
-                new PipSnapAlgorithm(), new PipKeepClearAlgorithm() {});
+                new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {});
         mMainExecutor = new TestShellExecutor();
         mPipTaskOrganizer = new PipTaskOrganizer(mContext,
                 mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index 3bd2ae7..c1993b2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -37,7 +37,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipKeepClearAlgorithm;
+import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
@@ -90,8 +90,8 @@
         MockitoAnnotations.initMocks(this);
         mPipBoundsState = new PipBoundsState(mContext);
         final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm();
-        final PipKeepClearAlgorithm pipKeepClearAlgorithm =
-                new PipKeepClearAlgorithm() {};
+        final PipKeepClearAlgorithmInterface pipKeepClearAlgorithm =
+                new PipKeepClearAlgorithmInterface() {};
         final PipBoundsAlgorithm pipBoundsAlgorithm = new PipBoundsAlgorithm(mContext,
                 mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm);
         final PipMotionHelper motionHelper = new PipMotionHelper(mContext, mPipBoundsState,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 474d6aa..8ad2932 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -34,7 +34,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipKeepClearAlgorithm;
+import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
@@ -106,7 +106,7 @@
         mPipBoundsState = new PipBoundsState(mContext);
         mPipSnapAlgorithm = new PipSnapAlgorithm();
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm,
-                new PipKeepClearAlgorithm() {});
+                new PipKeepClearAlgorithmInterface() {});
         PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState,
                 mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm,
                 mMockPipTransitionController, mFloatingContentCoordinator);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 273c7af..4323c73 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -708,12 +708,10 @@
          * It's easier to create it here than in C++.
          */
         try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {
-            native_setup(new WeakReference<MediaPlayer>(this), attributionSourceState.getParcel());
+            native_setup(new WeakReference<>(this), attributionSourceState.getParcel(),
+                    resolvePlaybackSessionId(context, sessionId));
         }
-
-        int effectiveSessionId = resolvePlaybackSessionId(context, sessionId);
-        baseRegisterPlayer(effectiveSessionId);
-        native_setAudioSessionId(effectiveSessionId);
+        baseRegisterPlayer(getAudioSessionId());
     }
 
     private Parcel createPlayerIIdParcel() {
@@ -1022,8 +1020,6 @@
             final AudioAttributes aa = audioAttributes != null ? audioAttributes :
                 new AudioAttributes.Builder().build();
             mp.setAudioAttributes(aa);
-            mp.native_setAudioSessionId(audioSessionId);
-
             mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
             afd.close();
             mp.prepare();
@@ -2521,7 +2517,7 @@
 
     private static native final void native_init();
     private native void native_setup(Object mediaplayerThis,
-            @NonNull Parcel attributionSource);
+            @NonNull Parcel attributionSource, int audioSessionId);
     private native final void native_finalize();
 
     /**
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index a1a6b51..a9ea6d3 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -33,11 +33,54 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TABLE_NAME_PAT, TABLE_NAME_PMT})
+    @IntDef({TABLE_NAME_PAT, TABLE_NAME_PMT, TABLE_NAME_CAT})
     public @interface TableName {}
 
+    /** Program Association Table */
     public static final int TABLE_NAME_PAT = 0;
+    /** Program Mapping Table */
     public static final int TABLE_NAME_PMT = 1;
+    /**
+     * Conditional Access Table
+     * @hide
+     */
+    public static final int TABLE_NAME_CAT = 2;
+    /**
+     * Network Information Table
+     * @hide
+     */
+    public static final int TABLE_NAME_NIT = 3;
+    /**
+     * Bouquet Association Table
+     * @hide
+     */
+    public static final int TABLE_NAME_BAT = 4;
+    /**
+     * Service Description Table
+     * @hide
+     */
+    public static final int TABLE_NAME_SDT = 5;
+    /**
+     * Event Information Table
+     * @hide
+     */
+    public static final int TABLE_NAME_EIT = 6;
+    /**
+     * Time and Date Table
+     * @hide
+     */
+    public static final int TABLE_NAME_TDT = 7;
+    /**
+     * Time Offset Table
+     * @hide
+     */
+    public static final int TABLE_NAME_TOT = 8;
+    /**
+     * Selection Information Table
+     * @hide
+     */
+    public static final int TABLE_NAME_SIT = 9;
+
 
     public static final @NonNull Parcelable.Creator<TableRequest> CREATOR =
             new Parcelable.Creator<TableRequest>() {
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index afc9bee..1c314b0 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -21,6 +21,7 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SharedMemory;
 
 /**
  * A response for Table from broadcast signal.
@@ -46,6 +47,8 @@
     private final Uri mTableUri;
     private final int mVersion;
     private final int mSize;
+    private final byte[] mTableByteArray;
+    private final SharedMemory mTableSharedMemory;
 
     static TableResponse createFromParcelBody(Parcel in) {
         return new TableResponse(in);
@@ -54,9 +57,33 @@
     public TableResponse(int requestId, int sequence, @ResponseResult int responseResult,
             @Nullable Uri tableUri, int version, int size) {
         super(RESPONSE_TYPE, requestId, sequence, responseResult);
-        mTableUri = tableUri;
         mVersion = version;
         mSize = size;
+        mTableUri = tableUri;
+        mTableByteArray = null;
+        mTableSharedMemory = null;
+    }
+
+    /** @hide */
+    public TableResponse(int requestId, int sequence, @ResponseResult int responseResult,
+            @NonNull byte[] tableByteArray, int version, int size) {
+        super(RESPONSE_TYPE, requestId, sequence, responseResult);
+        mVersion = version;
+        mSize = size;
+        mTableUri = null;
+        mTableByteArray = tableByteArray;
+        mTableSharedMemory = null;
+    }
+
+    /** @hide */
+    public TableResponse(int requestId, int sequence, @ResponseResult int responseResult,
+            @NonNull SharedMemory tableSharedMemory, int version, int size) {
+        super(RESPONSE_TYPE, requestId, sequence, responseResult);
+        mVersion = version;
+        mSize = size;
+        mTableUri = null;
+        mTableByteArray = null;
+        mTableSharedMemory = tableSharedMemory;
     }
 
     TableResponse(Parcel source) {
@@ -65,6 +92,14 @@
         mTableUri = uriString == null ? null : Uri.parse(uriString);
         mVersion = source.readInt();
         mSize = source.readInt();
+        int arrayLength = source.readInt();
+        if (arrayLength >= 0) {
+            mTableByteArray = new byte[arrayLength];
+            source.readByteArray(mTableByteArray);
+        } else {
+            mTableByteArray = null;
+        }
+        mTableSharedMemory = (SharedMemory) source.readTypedObject(SharedMemory.CREATOR);
     }
 
     /**
@@ -76,6 +111,30 @@
     }
 
     /**
+     * Gets the data of the table as a byte array.
+     *
+     * @return the table data as a byte array, or {@code null} if the data is not stored as a byte
+     *         array.
+     * @hide
+     */
+    @Nullable
+    public byte[] getTableByteArray() {
+        return mTableByteArray;
+    }
+
+    /**
+     * Gets the data of the table as a {@link SharedMemory} object.
+     *
+     * @return the table data as a {@link SharedMemory} object, or {@code null} if the data is not
+     *         stored in shared memory.
+     * @hide
+     */
+    @Nullable
+    public SharedMemory getTableSharedMemory() {
+        return mTableSharedMemory;
+    }
+
+    /**
      * Gets the version number of requested table. If it is null, value will be -1.
      * <p>The consistency of version numbers between request and response depends on
      * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
@@ -106,5 +165,12 @@
         dest.writeString(uriString);
         dest.writeInt(mVersion);
         dest.writeInt(mSize);
+        if (mTableByteArray != null) {
+            dest.writeInt(mTableByteArray.length);
+            dest.writeByteArray(mTableByteArray);
+        } else {
+            dest.writeInt(-1);
+        }
+        dest.writeTypedObject(mTableSharedMemory, flags);
     }
 }
diff --git a/media/java/android/media/tv/TimelineRequest.java b/media/java/android/media/tv/TimelineRequest.java
index 03c62f0..d04c58a 100644
--- a/media/java/android/media/tv/TimelineRequest.java
+++ b/media/java/android/media/tv/TimelineRequest.java
@@ -42,6 +42,7 @@
             };
 
     private final int mIntervalMillis;
+    private final String mSelector;
 
     static TimelineRequest createFromParcelBody(Parcel in) {
         return new TimelineRequest(in);
@@ -50,11 +51,21 @@
     public TimelineRequest(int requestId, @RequestOption int option, int intervalMillis) {
         super(REQUEST_TYPE, requestId, option);
         mIntervalMillis = intervalMillis;
+        mSelector = null;
+    }
+
+    /** @hide */
+    public TimelineRequest(int requestId, @RequestOption int option, int intervalMillis,
+            @NonNull String selector) {
+        super(REQUEST_TYPE, requestId, option);
+        mIntervalMillis = intervalMillis;
+        mSelector = selector;
     }
 
     TimelineRequest(Parcel source) {
         super(REQUEST_TYPE, source);
         mIntervalMillis = source.readInt();
+        mSelector = source.readString();
     }
 
     /**
@@ -64,6 +75,18 @@
         return mIntervalMillis;
     }
 
+    /**
+     * Gets the timeline selector.
+     * <p>The selector describes the type and location of timeline signalling. For example
+     * {@code urn:dvb:css:timeline:pts} is a selector in DVB standard.
+     *
+     * @return the selector if it's set; {@code null} otherwise.
+     * @hide
+     */
+    public String getSelector() {
+        return mSelector;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -73,5 +96,6 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeInt(mIntervalMillis);
+        dest.writeString(mSelector);
     }
 }
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index 494571f..ad9312f 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -43,6 +43,7 @@
     void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
     void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters, int seq);
     void onSetVideoBounds(in Rect rect, int seq);
+    void onRequestCurrentVideoBounds(int seq);
     void onRequestCurrentChannelUri(int seq);
     void onRequestCurrentChannelLcn(int seq);
     void onRequestStreamVolume(int seq);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index 1cfb6ef..c0723f7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -37,6 +37,7 @@
  */
 interface ITvInteractiveAppManager {
     List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId);
+    List<AppLinkInfo> getAppLinkInfoList(int userId);
     void registerAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
     void unregisterAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
     void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
@@ -47,6 +48,7 @@
             in IBinder sessionToken, in Uri biIAppUri, in Bundle params, int userId);
     void destroyBiInteractiveApp(in IBinder sessionToken, in String biIAppId, int userId);
     void setTeletextAppEnabled(in IBinder sessionToken, boolean enable, int userId);
+    void sendCurrentVideoBounds(in IBinder sessionToken, in Rect bounds, int userId);
     void sendCurrentChannelUri(in IBinder sessionToken, in Uri channelUri, int userId);
     void sendCurrentChannelLcn(in IBinder sessionToken, int lcn, int userId);
     void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index 17a70d1..9ae9ca7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -40,6 +40,7 @@
     void createBiInteractiveApp(in Uri biIAppUri, in Bundle params);
     void destroyBiInteractiveApp(in String biIAppId);
     void setTeletextAppEnabled(boolean enable);
+    void sendCurrentVideoBounds(in Rect bounds);
     void sendCurrentChannelUri(in Uri channelUri);
     void sendCurrentChannelLcn(int lcn);
     void sendStreamVolume(float volume);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index 0565742..d84affd 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -42,6 +42,7 @@
     void onCommandRequest(in String cmdType, in Bundle parameters);
     void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters);
     void onSetVideoBounds(in Rect rect);
+    void onRequestCurrentVideoBounds();
     void onRequestCurrentChannelUri();
     void onRequestCurrentChannelLcn();
     void onRequestStreamVolume();
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index b8158cd..8a23e65 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -94,6 +94,7 @@
     private static final int DO_NOTIFY_TIME_SHIFT_STATUS_CHANGED = 37;
     private static final int DO_NOTIFY_TIME_SHIFT_START_POSITION_CHANGED = 38;
     private static final int DO_NOTIFY_TIME_SHIFT_CURRENT_POSITION_CHANGED = 39;
+    private static final int DO_SEND_CURRENT_VIDEO_BOUNDS = 40;
 
     private final HandlerCaller mCaller;
     private Session mSessionImpl;
@@ -157,6 +158,10 @@
                 mSessionImpl.setTeletextAppEnabled((Boolean) msg.obj);
                 break;
             }
+            case DO_SEND_CURRENT_VIDEO_BOUNDS: {
+                mSessionImpl.sendCurrentVideoBounds((Rect) msg.obj);
+                break;
+            }
             case DO_SEND_CURRENT_CHANNEL_URI: {
                 mSessionImpl.sendCurrentChannelUri((Uri) msg.obj);
                 break;
@@ -355,6 +360,12 @@
     }
 
     @Override
+    public void sendCurrentVideoBounds(@Nullable Rect bounds) {
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageO(DO_SEND_CURRENT_VIDEO_BOUNDS, bounds));
+    }
+
+    @Override
     public void sendCurrentChannelUri(@Nullable Uri channelUri) {
         mCaller.executeOrSendMessage(
                 mCaller.obtainMessageO(DO_SEND_CURRENT_CHANNEL_URI, channelUri));
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 3647a9c..fd3c29b 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -445,6 +445,18 @@
             }
 
             @Override
+            public void onRequestCurrentVideoBounds(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestCurrentVideoBounds();
+                }
+            }
+
+            @Override
             public void onRequestCurrentChannelUri(int seq) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -865,6 +877,24 @@
     }
 
     /**
+     * Returns a list of available app link information.
+     *
+     * <P>A package must declare its app link info in its manifest using meta-data tag, so the info
+     * can be detected by the system.
+     *
+     * @return List of {@link AppLinkInfo} for each package that deslares its app link information.
+     * @hide
+     */
+    @NonNull
+    public List<AppLinkInfo> getAppLinkInfoList() {
+        try {
+            return mService.getAppLinkInfoList(mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Registers an Android application link info record which can be used to launch the specific
      * Android application by TV interactive App RTE.
      *
@@ -1066,6 +1096,18 @@
             }
         }
 
+        void sendCurrentVideoBounds(@NonNull Rect bounds) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.sendCurrentVideoBounds(mToken, bounds, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         void sendCurrentChannelUri(@Nullable Uri channelUri) {
             if (mToken == null) {
                 Log.w(TAG, "The session has been already released");
@@ -1880,6 +1922,15 @@
             });
         }
 
+        void postRequestCurrentVideoBounds() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestCurrentVideoBounds(mSession);
+                }
+            });
+        }
+
         void postRequestCurrentChannelUri() {
             mHandler.post(new Runnable() {
                 @Override
@@ -2101,6 +2152,15 @@
         }
 
         /**
+         * This is called when {@link TvInteractiveAppService.Session#RequestCurrentVideoBounds} is
+         * called.
+         *
+         * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
+         */
+        public void onRequestCurrentVideoBounds(Session session) {
+        }
+
+        /**
          * This is called when {@link TvInteractiveAppService.Session#RequestCurrentChannelUri} is
          * called.
          *
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 949e017..be2c16c 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -17,6 +17,7 @@
 package android.media.tv.interactive;
 
 import android.annotation.CallSuper;
+import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -139,6 +140,38 @@
      * Playback command type: select the given track.
      */
     public static final String PLAYBACK_COMMAND_TYPE_SELECT_TRACK = "select_track";
+
+
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "PLAYBACK_COMMAND_STOP_MODE_", value = {
+            PLAYBACK_COMMAND_STOP_MODE_BLANK,
+            PLAYBACK_COMMAND_STOP_MODE_FREEZE
+    })
+    public @interface PlaybackCommandStopMode {}
+
+    /**
+     * Playback command stop mode: show a blank screen.
+     * @hide
+     */
+    public static final int PLAYBACK_COMMAND_STOP_MODE_BLANK = 1;
+
+    /**
+     * Playback command stop mode: freeze the video.
+     * @hide
+     */
+    public static final int PLAYBACK_COMMAND_STOP_MODE_FREEZE = 2;
+
+    /**
+     * Playback command parameter: stop mode.
+     * <p>Type: int
+     *
+     * @see #PLAYBACK_COMMAND_TYPE_STOP
+     * @hide
+     */
+    public static final String COMMAND_PARAMETER_KEY_STOP_MODE = "command_stop_mode";
+
     /**
      * Playback command parameter: channel URI.
      * <p>Type: android.net.Uri
@@ -498,6 +531,13 @@
         }
 
         /**
+         * Receives current video bounds.
+         * @hide
+         */
+        public void onCurrentVideoBounds(@NonNull Rect bounds) {
+        }
+
+        /**
          * Receives current channel URI.
          */
         public void onCurrentChannelUri(@Nullable Uri channelUri) {
@@ -983,6 +1023,30 @@
         }
 
         /**
+         * Requests the bounds of the current video.
+         * @hide
+         */
+        @CallSuper
+        public void requestCurrentVideoBounds() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestCurrentVideoBounds");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestCurrentVideoBounds();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestCurrentVideoBounds", e);
+                    }
+                }
+            });
+        }
+
+        /**
          * Requests the URI of the current channel.
          */
         @CallSuper
@@ -1309,6 +1373,10 @@
             onSetTeletextAppEnabled(enable);
         }
 
+        void sendCurrentVideoBounds(@NonNull Rect bounds) {
+            onCurrentVideoBounds(bounds);
+        }
+
         void sendCurrentChannelUri(@Nullable Uri channelUri) {
             onCurrentChannelUri(channelUri);
         }
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
index 3e08852..acc2444 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
@@ -57,6 +57,8 @@
             INTERACTIVE_APP_TYPE_HBBTV,
             INTERACTIVE_APP_TYPE_ATSC,
             INTERACTIVE_APP_TYPE_GINGA,
+            INTERACTIVE_APP_TYPE_TARGETED_AD,
+            INTERACTIVE_APP_TYPE_OTHER
     })
     public @interface InteractiveAppType {}
 
@@ -66,10 +68,21 @@
     public static final int INTERACTIVE_APP_TYPE_ATSC = 0x2;
     /** Ginga interactive app type */
     public static final int INTERACTIVE_APP_TYPE_GINGA = 0x4;
+    /**
+     * Targeted Advertisement interactive app type
+     * @hide
+     */
+    public static final int INTERACTIVE_APP_TYPE_TARGETED_AD = 0x8;
+    /**
+     * Other interactive app type
+     * @hide
+     */
+    public static final int INTERACTIVE_APP_TYPE_OTHER = 0x80000000;
 
     private final ResolveInfo mService;
     private final String mId;
     private int mTypes;
+    private final List<String> mExtraTypes = new ArrayList<>();
 
     /**
      * Constructs a TvInteractiveAppServiceInfo object.
@@ -98,18 +111,21 @@
 
         mService = resolveInfo;
         mId = id;
-        mTypes = toTypesFlag(types);
+        toTypesFlag(types);
     }
-    private TvInteractiveAppServiceInfo(ResolveInfo service, String id, int types) {
+    private TvInteractiveAppServiceInfo(
+            ResolveInfo service, String id, int types, List<String> extraTypes) {
         mService = service;
         mId = id;
         mTypes = types;
+        mExtraTypes.addAll(extraTypes);
     }
 
     private TvInteractiveAppServiceInfo(@NonNull Parcel in) {
         mService = ResolveInfo.CREATOR.createFromParcel(in);
         mId = in.readString();
         mTypes = in.readInt();
+        in.readStringList(mExtraTypes);
     }
 
     public static final @NonNull Creator<TvInteractiveAppServiceInfo> CREATOR =
@@ -135,6 +151,7 @@
         mService.writeToParcel(dest, flags);
         dest.writeString(mId);
         dest.writeInt(mTypes);
+        dest.writeStringList(mExtraTypes);
     }
 
     /**
@@ -171,6 +188,17 @@
         return mTypes;
     }
 
+    /**
+     * Gets extra supported interactive app types which are not listed.
+     *
+     * @see #getSupportedTypes()
+     * @hide
+     */
+    @NonNull
+    public List<String> getExtraSupportedTypes() {
+        return mExtraTypes;
+    }
+
     private static String generateInteractiveAppServiceId(ComponentName name) {
         return name.flattenToShortString();
     }
@@ -219,23 +247,27 @@
         }
     }
 
-    private static int toTypesFlag(List<String> types) {
-        int flag = 0;
+    private void toTypesFlag(List<String> types) {
+        mTypes = 0;
+        mExtraTypes.clear();
         for (String type : types) {
             switch (type) {
                 case "hbbtv":
-                    flag |= INTERACTIVE_APP_TYPE_HBBTV;
+                    mTypes |= INTERACTIVE_APP_TYPE_HBBTV;
                     break;
                 case "atsc":
-                    flag |= INTERACTIVE_APP_TYPE_ATSC;
+                    mTypes |= INTERACTIVE_APP_TYPE_ATSC;
                     break;
                 case "ginga":
-                    flag |= INTERACTIVE_APP_TYPE_GINGA;
+                    mTypes |= INTERACTIVE_APP_TYPE_GINGA;
                     break;
+                case "targeted_ad":
+                    mTypes |= INTERACTIVE_APP_TYPE_TARGETED_AD;
                 default:
+                    mTypes |= INTERACTIVE_APP_TYPE_OTHER;
+                    mExtraTypes.add(type);
                     break;
             }
         }
-        return flag;
     }
 }
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 9211a12..af03bb8 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -514,6 +514,19 @@
     }
 
     /**
+     * Sends current video bounds to related TV interactive app.
+     * @hide
+     */
+    public void sendCurrentVideoBounds(@NonNull Rect bounds) {
+        if (DEBUG) {
+            Log.d(TAG, "sendCurrentVideoBounds");
+        }
+        if (mSession != null) {
+            mSession.sendCurrentVideoBounds(bounds);
+        }
+    }
+
+    /**
      * Sends current channel URI to related TV interactive app.
      *
      * @param channelUri The current channel URI; {@code null} if there is no currently tuned
@@ -944,6 +957,16 @@
         }
 
         /**
+         * This is called when {@link TvInteractiveAppService.Session#requestCurrentVideoBounds()}
+         * is called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @hide
+         */
+        public void onRequestCurrentVideoBounds(@NonNull String iAppServiceId) {
+        }
+
+        /**
          * This is called when {@link TvInteractiveAppService.Session#requestCurrentChannelUri()} is
          * called.
          *
@@ -1265,6 +1288,28 @@
         }
 
         @Override
+        public void onRequestCurrentVideoBounds(Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestCurrentVideoBounds");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestCurrentVideoBounds - session not created");
+                return;
+            }
+            synchronized (mCallbackLock) {
+                if (mCallbackExecutor != null) {
+                    mCallbackExecutor.execute(() -> {
+                        synchronized (mCallbackLock) {
+                            if (mCallback != null) {
+                                mCallback.onRequestCurrentVideoBounds(mIAppServiceId);
+                            }
+                        }
+                    });
+                }
+            }
+        }
+
+        @Override
         public void onRequestCurrentChannelUri(Session session) {
             if (DEBUG) {
                 Log.d(TAG, "onRequestCurrentChannelUri");
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index da920bb..9552200 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -956,14 +956,16 @@
 
 static void
 android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-                                       jobject jAttributionSource)
+                                       jobject jAttributionSource,
+                                       jint jAudioSessionId)
 {
     ALOGV("native_setup");
 
     Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
     android::content::AttributionSourceState attributionSource;
     attributionSource.readFromParcel(parcel);
-    sp<MediaPlayer> mp = sp<MediaPlayer>::make(attributionSource);
+    sp<MediaPlayer> mp = sp<MediaPlayer>::make(
+        attributionSource, static_cast<audio_session_t>(jAudioSessionId));
     if (mp == NULL) {
         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
         return;
@@ -1419,7 +1421,9 @@
     {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
     {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
     {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
-    {"native_setup",        "(Ljava/lang/Object;Landroid/os/Parcel;)V",(void *)android_media_MediaPlayer_native_setup},
+    {"native_setup",
+        "(Ljava/lang/Object;Landroid/os/Parcel;I)V",
+        (void *)android_media_MediaPlayer_native_setup},
     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
     {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
     {"native_setAudioSessionId",   "(I)V",                      (void *)android_media_MediaPlayer_set_audio_session_id},
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java
index f480566..f812d5f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerUnitTest.java
@@ -23,6 +23,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -56,6 +57,7 @@
         MediaPlayer mediaPlayer = new MediaPlayer(virtualDeviceContext);
 
         assertNotEquals(vdmPlaybackSessionId, mediaPlayer.getAudioSessionId());
+        assertTrue(mediaPlayer.getAudioSessionId() > 0);
     }
 
     @Test
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 1e7fc93..197cf56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -54,7 +54,7 @@
  * their respective views based on the progress of the animator. Interpolation differences TBD
  */
 @SysUISingleton
-class SystemStatusAnimationScheduler @Inject constructor(
+open class SystemStatusAnimationScheduler @Inject constructor(
     private val coordinator: SystemEventCoordinator,
     private val chipAnimationController: SystemEventChipAnimationController,
     private val statusBarWindowController: StatusBarWindowController,
@@ -66,7 +66,7 @@
     companion object {
         private const val PROPERTY_ENABLE_IMMERSIVE_INDICATOR = "enable_immersive_indicator"
     }
-    private fun isImmersiveIndicatorEnabled(): Boolean {
+    public fun isImmersiveIndicatorEnabled(): Boolean {
         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                 PROPERTY_ENABLE_IMMERSIVE_INDICATOR, true)
     }
@@ -76,18 +76,22 @@
 
     /** True if the persistent privacy dot should be active */
     var hasPersistentDot = false
-        private set
+        protected set
 
     private var scheduledEvent: StatusEvent? = null
     private var cancelExecutionRunnable: Runnable? = null
     private val listeners = mutableSetOf<SystemStatusAnimationCallback>()
 
+    fun getListeners(): MutableSet<SystemStatusAnimationCallback> {
+        return listeners
+    }
+
     init {
         coordinator.attachScheduler(this)
         dumpManager.registerDumpable(TAG, this)
     }
 
-    fun onStatusEvent(event: StatusEvent) {
+    open fun onStatusEvent(event: StatusEvent) {
         // Ignore any updates until the system is up and running
         if (isTooEarly() || !isImmersiveIndicatorEnabled()) {
             return
@@ -139,7 +143,7 @@
         }
     }
 
-    private fun isTooEarly(): Boolean {
+    public fun isTooEarly(): Boolean {
         return systemClock.uptimeMillis() - Process.getStartUptimeMillis() < MIN_UPTIME
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 010189a..b28ab7a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3248,7 +3248,7 @@
         if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) {
             final boolean enabled =
                     !getMagnificationController().getFullScreenMagnificationController()
-                            .isMagnifying(displayId);
+                            .isActivated(displayId);
             logAccessibilityShortcutActivated(mContext, MAGNIFICATION_COMPONENT_NAME, shortcutType,
                     enabled);
             sendAccessibilityButtonToInputFilter(displayId);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 6cfbfb8..de7184c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -126,8 +126,6 @@
         private boolean mUnregisterPending;
         private boolean mDeleteAfterUnregister;
 
-        private boolean mForceShowMagnifiableBounds;
-
         private final int mDisplayId;
 
         private int mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
@@ -213,8 +211,8 @@
             return mRegistered;
         }
 
-        boolean isMagnifying() {
-            return mCurrentMagnificationSpec.scale > 1.0f;
+        boolean isActivated() {
+            return mMagnificationActivated;
         }
 
         float getScale() {
@@ -370,12 +368,6 @@
         @GuardedBy("mLock")
         void onMagnificationChangedLocked() {
             final float scale = getScale();
-            final boolean lastMagnificationActivated = mMagnificationActivated;
-            mMagnificationActivated = scale > 1.0f;
-            if (mMagnificationActivated != lastMagnificationActivated) {
-                mMagnificationInfoChangedCallback.onFullScreenMagnificationActivationState(
-                        mDisplayId, mMagnificationActivated);
-            }
 
             final MagnificationConfig config = new MagnificationConfig.Builder()
                     .setMode(MAGNIFICATION_MODE_FULLSCREEN)
@@ -384,7 +376,7 @@
                     .setCenterY(getCenterY()).build();
             mMagnificationInfoChangedCallback.onFullScreenMagnificationChanged(mDisplayId,
                     mMagnificationRegion, config);
-            if (mUnregisterPending && !isMagnifying()) {
+            if (mUnregisterPending && !isActivated()) {
                 unregister(mDeleteAfterUnregister);
             }
         }
@@ -476,21 +468,22 @@
         }
 
         @GuardedBy("mLock")
-        void setForceShowMagnifiableBounds(boolean show) {
-            if (mRegistered) {
-                mForceShowMagnifiableBounds = show;
-                if (traceEnabled()) {
-                    logTrace("setForceShowMagnifiableBounds",
-                            "displayID=" + mDisplayId + ";show=" + show);
-                }
-                mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
-                        mDisplayId, show);
+        private boolean setActivated(boolean activated) {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "setActivated(activated = " + activated + ")");
             }
-        }
 
-        @GuardedBy("mLock")
-        boolean isForceShowMagnifiableBounds() {
-            return mRegistered && mForceShowMagnifiableBounds;
+            final boolean changed = (mMagnificationActivated != activated);
+
+            if (changed) {
+                mMagnificationActivated = activated;
+                mMagnificationInfoChangedCallback.onFullScreenMagnificationActivationState(
+                        mDisplayId, mMagnificationActivated);
+                mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
+                        mDisplayId, activated);
+            }
+
+            return changed;
         }
 
         @GuardedBy("mLock")
@@ -504,13 +497,13 @@
                 return false;
             }
             final MagnificationSpec spec = mCurrentMagnificationSpec;
-            final boolean changed = !spec.isNop();
+            final boolean changed = isActivated();
+            setActivated(false);
             if (changed) {
                 spec.clear();
                 onMagnificationChangedLocked();
             }
             mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
-            mForceShowMagnifiableBounds = false;
             sendSpecToAnimation(spec, animationCallback);
             return changed;
         }
@@ -554,9 +547,10 @@
                                 + ", centerY = " + centerY + ", endCallback = "
                                 + animationCallback + ", id = " + id + ")");
             }
-            final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
+            boolean changed = setActivated(true);
+            changed |= updateMagnificationSpecLocked(scale, centerX, centerY);
             sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
-            if (isMagnifying() && (id != INVALID_SERVICE_ID)) {
+            if (isActivated() && (id != INVALID_SERVICE_ID)) {
                 mIdOfLastServiceToMagnify = id;
                 mMagnificationInfoChangedCallback.onRequestMagnificationSpec(mDisplayId,
                         mIdOfLastServiceToMagnify);
@@ -779,7 +773,7 @@
             if (display == null) {
                 return;
             }
-            if (!display.isMagnifying()) {
+            if (!display.isActivated()) {
                 return;
             }
             final Rect magnifiedRegionBounds = mTempRect;
@@ -831,16 +825,16 @@
 
     /**
      * @param displayId The logical display id.
-     * @return {@code true} if magnification is active, e.g. the scale
-     *         is > 1, {@code false} otherwise
+     * @return {@code true} if magnification is activated,
+     *         {@code false} otherwise
      */
-    public boolean isMagnifying(int displayId) {
+    public boolean isActivated(int displayId) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
             if (display == null) {
                 return false;
             }
-            return display.isMagnifying();
+            return display.isActivated();
         }
     }
 
@@ -1166,6 +1160,9 @@
      */
     public void persistScale(int displayId) {
         final float scale = getScale(Display.DEFAULT_DISPLAY);
+        if (scale < 2.0f) {
+            return;
+        }
         mScaleProvider.putScale(scale, displayId);
     }
 
@@ -1177,7 +1174,8 @@
      *         scale if none is available
      */
     public float getPersistedScale(int displayId) {
-        return mScaleProvider.getScale(displayId);
+        return MathUtils.constrain(mScaleProvider.getScale(displayId),
+                2.0f, MagnificationScaleProvider.MAX_SCALE);
     }
 
     /**
@@ -1198,12 +1196,12 @@
      *
      * @param displayId The logical display id.
      * @param animate whether the animate the transition
-     * @return whether was {@link #isMagnifying(int) magnifying}
+     * @return whether was {@link #isActivated(int)}  activated}
      */
     boolean resetIfNeeded(int displayId, boolean animate) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
-            if (display == null || !display.isMagnifying()) {
+            if (display == null || !display.isActivated()) {
                 return false;
             }
             display.reset(animate);
@@ -1221,7 +1219,7 @@
     boolean resetIfNeeded(int displayId, int connectionId) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
-            if (display == null || !display.isMagnifying()
+            if (display == null || !display.isActivated()
                     || connectionId != display.getIdOfLastServiceToMagnify()) {
                 return false;
             }
@@ -1230,16 +1228,6 @@
         }
     }
 
-    void setForceShowMagnifiableBounds(int displayId, boolean show) {
-        synchronized (mLock) {
-            final DisplayMagnification display = mDisplays.get(displayId);
-            if (display == null) {
-                return;
-            }
-            display.setForceShowMagnifiableBounds(show);
-        }
-    }
-
     /**
      * Notifies that the IME window visibility changed.
      *
@@ -1251,21 +1239,6 @@
         mMagnificationInfoChangedCallback.onImeWindowVisibilityChanged(displayId, shown);
     }
 
-    /**
-     * Returns {@code true} if the magnifiable regions of the display is forced to be shown.
-     *
-     * @param displayId The logical display id.
-     */
-    public boolean isForceShowMagnifiableBounds(int displayId) {
-        synchronized (mLock) {
-            final DisplayMagnification display = mDisplays.get(displayId);
-            if (display == null) {
-                return false;
-            }
-            return display.isForceShowMagnifiableBounds();
-        }
-    }
-
     private void onScreenTurnedOff() {
         final Message m = PooledLambda.obtainMessage(
                 FullScreenMagnificationController::resetAllIfNeeded, this, false);
@@ -1295,7 +1268,7 @@
             }
             return;
         }
-        if (!display.isMagnifying()) {
+        if (!display.isActivated()) {
             display.unregister(delete);
         } else {
             display.unregisterPending(delete);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index dc39b01..6bf37a1 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -122,7 +122,7 @@
     // The MIN_SCALE is different from MagnificationScaleProvider.MIN_SCALE due
     // to AccessibilityService.MagnificationController#setScale() has
     // different scale range
-    private static final float MIN_SCALE = 2.0f;
+    private static final float MIN_SCALE = 1.0f;
     private static final float MAX_SCALE = MagnificationScaleProvider.MAX_SCALE;
 
     @VisibleForTesting final FullScreenMagnificationController mFullScreenMagnificationController;
@@ -220,14 +220,19 @@
 
     @Override
     public void handleShortcutTriggered() {
-        boolean wasMagnifying = mFullScreenMagnificationController.resetIfNeeded(mDisplayId,
-                /* animate */ true);
-        if (wasMagnifying) {
+        final boolean isActivated = mFullScreenMagnificationController.isActivated(mDisplayId);
+
+        if (isActivated) {
+            zoomOff();
             clearAndTransitionToStateDetecting();
         } else {
-            mPromptController.showNotificationIfNeeded();
             mDetectingState.toggleShortcutTriggered();
         }
+
+        if (mDetectingState.isShortcutTriggered()) {
+            mPromptController.showNotificationIfNeeded();
+            zoomToScale(1.0f, Float.NaN, Float.NaN);
+        }
     }
 
     @Override
@@ -441,7 +446,12 @@
     final class ViewportDraggingState implements State {
 
         /** Whether to disable zoom after dragging ends */
-        boolean mZoomedInBeforeDrag;
+        @VisibleForTesting boolean mActivatedBeforeDrag;
+        /** Whether to restore scale after dragging ends */
+        private boolean mZoomedInTemporary;
+        /** The cached scale for recovering after dragging ends */
+        private float mScaleBeforeZoomedInTemporary;
+
         private boolean mLastMoveOutsideMagnifiedRegion;
 
         @Override
@@ -474,7 +484,13 @@
 
                 case ACTION_UP:
                 case ACTION_CANCEL: {
-                    if (!mZoomedInBeforeDrag) zoomOff();
+                    if (mActivatedBeforeDrag) {
+                        if (mZoomedInTemporary) {
+                            zoomToScale(mScaleBeforeZoomedInTemporary, event.getX(), event.getY());
+                        }
+                    } else {
+                        zoomOff();
+                    }
                     clear();
                     transitionTo(mDetectingState);
                 }
@@ -488,15 +504,27 @@
             }
         }
 
+        public void prepareForZoomInTemporary() {
+            mViewportDraggingState.mActivatedBeforeDrag =
+                    mFullScreenMagnificationController.isActivated(mDisplayId);
+
+            mViewportDraggingState.mZoomedInTemporary = true;
+            mViewportDraggingState.mScaleBeforeZoomedInTemporary =
+                    mFullScreenMagnificationController.getScale(mDisplayId);
+        }
+
         @Override
         public void clear() {
             mLastMoveOutsideMagnifiedRegion = false;
+
+            mZoomedInTemporary = false;
+            mScaleBeforeZoomedInTemporary = 1.0f;
         }
 
         @Override
         public String toString() {
             return "ViewportDraggingState{"
-                    + "mZoomedInBeforeDrag=" + mZoomedInBeforeDrag
+                    + "mActivatedBeforeDrag=" + mActivatedBeforeDrag
                     + ", mLastMoveOutsideMagnifiedRegion=" + mLastMoveOutsideMagnifiedRegion
                     + '}';
         }
@@ -625,10 +653,10 @@
                         transitionToDelegatingStateAndClear();
 
                     } else if (mDetectTripleTap
-                            // If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay
+                            // If activated, delay an ACTION_DOWN for mMultiTapMaxDelay
                             // to ensure reachability of
                             // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
-                            || mFullScreenMagnificationController.isMagnifying(mDisplayId)) {
+                            || isActivated()) {
 
                         afterMultiTapTimeoutTransitionToDelegatingState();
 
@@ -640,8 +668,7 @@
                 }
                 break;
                 case ACTION_POINTER_DOWN: {
-                    if (mFullScreenMagnificationController.isMagnifying(mDisplayId)
-                            && event.getPointerCount() == 2) {
+                    if (isActivated() && event.getPointerCount() == 2) {
                         storeSecondPointerDownLocation(event);
                         mHandler.sendEmptyMessageDelayed(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
                                 ViewConfiguration.getTapTimeout());
@@ -665,13 +692,13 @@
                         // (which is a rare combo to be used aside from magnification)
                         if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
                             transitionToViewportDraggingStateAndClear(event);
-                        } else if (isMagnifying() && event.getPointerCount() == 2) {
+                        } else if (isActivated() && event.getPointerCount() == 2) {
                             //Primary pointer is swiping, so transit to PanningScalingState
                             transitToPanningScalingStateAndClear();
                         } else {
                             transitionToDelegatingStateAndClear();
                         }
-                    } else if (isMagnifying() && secondPointerDownValid()
+                    } else if (isActivated() && secondPointerDownValid()
                             && distanceClosestPointerToPoint(
                             mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) {
                         //Second pointer is swiping, so transit to PanningScalingState
@@ -734,7 +761,7 @@
 
             // Only log the triple tap event, use numTaps to filter.
             if (multitapTriggered && numTaps > 2) {
-                final boolean enabled = mFullScreenMagnificationController.isMagnifying(mDisplayId);
+                final boolean enabled = isActivated();
                 logMagnificationTripleTap(enabled);
             }
             return multitapTriggered;
@@ -862,24 +889,33 @@
             mSecondPointerDownLocation.set(Float.NaN, Float.NaN);
         }
 
+        /**
+         * This method could be triggered by both 2 cases.
+         *      1. direct three tap gesture
+         *      2. one tap while shortcut triggered (it counts as two taps).
+         */
         private void onTripleTap(MotionEvent up) {
             if (DEBUG_DETECTING) {
                 Slog.i(mLogTag, "onTripleTap(); delayed: "
                         + MotionEventInfo.toString(mDelayedEventQueue));
             }
-            clear();
 
-            // Toggle zoom
-            if (mFullScreenMagnificationController.isMagnifying(mDisplayId)) {
-                zoomOff();
-            } else {
+            // We put mShortcutTriggered into conditions.
+            // The reason is when the shortcut is triggered,
+            //   the magnifier is activated and keeps in scale 1.0,
+            //   and in this case, we still want to zoom on the magnifier.
+            if (!isActivated() || mShortcutTriggered) {
                 mPromptController.showNotificationIfNeeded();
                 zoomOn(up.getX(), up.getY());
+            } else {
+                zoomOff();
             }
+
+            clear();
         }
 
-        private boolean isMagnifying() {
-            return mFullScreenMagnificationController.isMagnifying(mDisplayId);
+        private boolean isActivated() {
+            return mFullScreenMagnificationController.isActivated(mDisplayId);
         }
 
         void transitionToViewportDraggingStateAndClear(MotionEvent down) {
@@ -887,14 +923,13 @@
             if (DEBUG_DETECTING) Slog.i(mLogTag, "onTripleTapAndHold()");
             clear();
 
-            mViewportDraggingState.mZoomedInBeforeDrag =
-                    mFullScreenMagnificationController.isMagnifying(mDisplayId);
-
             // Triple tap and hold also belongs to triple tap event.
-            final boolean enabled = !mViewportDraggingState.mZoomedInBeforeDrag;
+            final boolean enabled = !isActivated();
             logMagnificationTripleTap(enabled);
 
-            zoomOn(down.getX(), down.getY());
+            mViewportDraggingState.prepareForZoomInTemporary();
+
+            zoomInTemporary(down.getX(), down.getY());
 
             transitionTo(mViewportDraggingState);
         }
@@ -919,7 +954,10 @@
             if (DEBUG_DETECTING) Slog.i(mLogTag, "setShortcutTriggered(" + state + ")");
 
             mShortcutTriggered = state;
-            mFullScreenMagnificationController.setForceShowMagnifiableBounds(mDisplayId, state);
+        }
+
+        private boolean isShortcutTriggered() {
+            return mShortcutTriggered;
         }
 
         /**
@@ -948,12 +986,29 @@
         }
     }
 
+    private void zoomInTemporary(float centerX, float centerY) {
+        final float currentScale = mFullScreenMagnificationController.getScale(mDisplayId);
+        final float persistedScale = MathUtils.constrain(
+                mFullScreenMagnificationController.getPersistedScale(mDisplayId),
+                MIN_SCALE, MAX_SCALE);
+
+        final float scale = MathUtils.constrain(Math.max(currentScale + 1.0f, persistedScale),
+                MIN_SCALE, MAX_SCALE);
+
+        zoomToScale(scale, centerX, centerY);
+    }
+
     private void zoomOn(float centerX, float centerY) {
         if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOn(" + centerX + ", " + centerY + ")");
 
         final float scale = MathUtils.constrain(
                 mFullScreenMagnificationController.getPersistedScale(mDisplayId),
                 MIN_SCALE, MAX_SCALE);
+        zoomToScale(scale, centerX, centerY);
+    }
+
+    private void zoomToScale(float scale, float centerX, float centerY) {
+        scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
         mFullScreenMagnificationController.setScaleAndCenter(mDisplayId,
                 scale, centerX, centerY,
                 /* animate */ true,
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 02e810f..129bc16 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -254,13 +254,15 @@
         final DisableMagnificationCallback animationEndCallback =
                 new DisableMagnificationCallback(transitionCallBack, displayId, targetMode,
                         scale, currentCenter, true);
+
+        setDisableMagnificationCallbackLocked(displayId, animationEndCallback);
+
         if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
             screenMagnificationController.reset(displayId, animationEndCallback);
         } else {
             windowMagnificationMgr.disableWindowMagnification(displayId, false,
                     animationEndCallback);
         }
-        setDisableMagnificationCallbackLocked(displayId, animationEndCallback);
     }
 
     /**
@@ -481,17 +483,17 @@
      */
     private boolean shouldNotifyMagnificationChange(int displayId, int changeMode) {
         synchronized (mLock) {
-            final boolean fullScreenMagnifying = mFullScreenMagnificationController != null
-                    && mFullScreenMagnificationController.isMagnifying(displayId);
+            final boolean fullScreenActivated = mFullScreenMagnificationController != null
+                    && mFullScreenMagnificationController.isActivated(displayId);
             final boolean windowEnabled = mWindowMagnificationMgr != null
                     && mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
             final Integer transitionMode = mTransitionModes.get(displayId);
-            if (((changeMode == MAGNIFICATION_MODE_FULLSCREEN && fullScreenMagnifying)
+            if (((changeMode == MAGNIFICATION_MODE_FULLSCREEN && fullScreenActivated)
                     || (changeMode == MAGNIFICATION_MODE_WINDOW && windowEnabled))
                     && (transitionMode == null)) {
                 return true;
             }
-            if ((!fullScreenMagnifying && !windowEnabled)
+            if ((!fullScreenActivated && !windowEnabled)
                     && (transitionMode == null)) {
                 return true;
             }
@@ -742,7 +744,7 @@
                     mWindowMagnificationMgr.getCenterY(displayId));
         } else {
             if (mFullScreenMagnificationController == null
-                    || !mFullScreenMagnificationController.isMagnifying(displayId)) {
+                    || !mFullScreenMagnificationController.isActivated(displayId)) {
                 return null;
             }
             mTempPoint.set(mFullScreenMagnificationController.getCenterX(displayId),
@@ -766,9 +768,7 @@
                 if (mFullScreenMagnificationController == null) {
                     return false;
                 }
-                isActivated = mFullScreenMagnificationController.isMagnifying(displayId)
-                        || mFullScreenMagnificationController.isForceShowMagnifiableBounds(
-                        displayId);
+                isActivated = mFullScreenMagnificationController.isActivated(displayId);
             }
         } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
             synchronized (mLock) {
@@ -829,7 +829,7 @@
                     final FullScreenMagnificationController screenMagnificationController =
                             getFullScreenMagnificationController();
                     if (mCurrentMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
-                            && !screenMagnificationController.isMagnifying(mDisplayId)) {
+                            && !screenMagnificationController.isActivated(mDisplayId)) {
                         MagnificationConfig.Builder configBuilder =
                                 new MagnificationConfig.Builder();
                         Region region = new Region();
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
index a356ae6..75fe026 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
@@ -313,13 +313,13 @@
     }
 
     /**
-     * {@link FullScreenMagnificationController#isMagnifying(int)}
+     * {@link FullScreenMagnificationController#isActivated(int)}
      * {@link WindowMagnificationManager#isWindowMagnifierEnabled(int)}
      */
     public boolean isMagnifying(int displayId) {
         int mode = getControllingMode(displayId);
         if (mode == MAGNIFICATION_MODE_FULLSCREEN) {
-            return mController.getFullScreenMagnificationController().isMagnifying(displayId);
+            return mController.getFullScreenMagnificationController().isActivated(displayId);
         } else if (mode == MAGNIFICATION_MODE_WINDOW) {
             return mController.getWindowMagnificationMgr().isWindowMagnifierEnabled(displayId);
         }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 17b6f5d..ec09acd 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -170,7 +170,7 @@
         "android.hardware.ir-V1-java",
         "android.hardware.rebootescrow-V1-java",
         "android.hardware.soundtrigger-V2.3-java",
-        "android.hardware.power.stats-V1-java",
+        "android.hardware.power.stats-V2-java",
         "android.hardware.power-V4-java",
         "android.hidl.manager-V1.2-java",
         "icu4j_calendar_astronomer",
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 68722d2..d485441 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -29,8 +29,11 @@
 import android.compat.annotation.ChangeId;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ApexStagedEvent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IBackgroundInstallControlService;
+import android.content.pm.IPackageManagerNative;
+import android.content.pm.IStagedApexObserver;
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
@@ -129,7 +132,6 @@
     private String mVbmetaDigest;
     // the system time (in ms) the last measurement was taken
     private long mMeasurementsLastRecordedMs;
-    private PackageManagerInternal mPackageManagerInternal;
 
     /**
      * Guards whether or not measurements of MBA to be performed. When this change is enabled,
@@ -1047,7 +1049,6 @@
         mServiceImpl = new BinaryTransparencyServiceImpl();
         mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED;
         mMeasurementsLastRecordedMs = 0;
-        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
     }
 
     /**
@@ -1062,38 +1063,6 @@
         } catch (Throwable t) {
             Slog.e(TAG, "Failed to start BinaryTransparencyService.", t);
         }
-
-        // register a package observer to detect updates to preloads
-        mPackageManagerInternal.getPackageList(new PackageManagerInternal.PackageListObserver() {
-            @Override
-            public void onPackageAdded(String packageName, int uid) {
-
-            }
-
-            @Override
-            public void onPackageChanged(String packageName, int uid) {
-                // check if the updated package is a preloaded app.
-                PackageManager pm = mContext.getPackageManager();
-                try {
-                    pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(
-                            PackageManager.MATCH_FACTORY_ONLY));
-                } catch (PackageManager.NameNotFoundException e) {
-                    // this means that this package is not a preloaded app
-                    return;
-                }
-
-                Slog.d(TAG, "Preload " + packageName + " was updated. Scheduling measurement...");
-                UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
-                        BinaryTransparencyService.this);
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-
-            }
-        });
-
-        // TODO(b/264428429): Register observer for updates to APEXs.
     }
 
     /**
@@ -1104,19 +1073,22 @@
      */
     @Override
     public void onBootPhase(int phase) {
-
-        // we are only interested in doing things at PHASE_BOOT_COMPLETED
-        if (phase == PHASE_BOOT_COMPLETED) {
-            Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
-            getVBMetaDigestInformation();
-
-            // to avoid the risk of holding up boot time, computations to measure APEX, Module, and
-            // MBA digests are scheduled here, but only executed when the device is idle and plugged
-            // in.
-            Slog.i(TAG, "Scheduling measurements to be taken.");
-            UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
-                    BinaryTransparencyService.this);
+        // so far we are only doing things in the PHASE_BOOT_COMPLETED phase
+        if (phase != PHASE_BOOT_COMPLETED) {
+            return;
         }
+
+        Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
+        getVBMetaDigestInformation();
+
+        // to avoid the risk of holding up boot time, computations to measure APEX, Module, and
+        // MBA digests are scheduled here, but only executed when the device is idle and plugged
+        // in.
+        Slog.i(TAG, "Scheduling measurements to be taken.");
+        UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
+                BinaryTransparencyService.this);
+
+        registerPackageUpdateObservers();
     }
 
     /**
@@ -1212,6 +1184,67 @@
         FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
     }
 
+    /**
+     * Register observers for APK and APEX updates.
+     * The observers will be invoked when i) APK update and ii) APEX staging happens. This will
+     * then be used as signals to schedule measurement for the relevant binaries.
+     */
+    private void registerPackageUpdateObservers() {
+        Slog.d(TAG, "Registering APK updates...");
+        // first, register a package observer to detect updates to preloads
+        PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        pmi.getPackageList(new PackageManagerInternal.PackageListObserver() {
+            @Override
+            public void onPackageAdded(String packageName, int uid) {
+            }
+
+            @Override
+            public void onPackageChanged(String packageName, int uid) {
+                // check if the updated package is a preloaded app.
+                PackageManager pm = mContext.getPackageManager();
+                try {
+                    pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(
+                            PackageManager.MATCH_FACTORY_ONLY));
+                } catch (PackageManager.NameNotFoundException e) {
+                    // this means that this package is not a preloaded app
+                    return;
+                }
+
+                Slog.d(TAG, "Preload " + packageName + " was updated. Scheduling measurement...");
+                UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
+                        BinaryTransparencyService.this);
+            }
+
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+            }
+        });
+
+        // then, register an observer for staged APEXs
+        Slog.d(TAG, "Registering APEX updates...");
+        IPackageManagerNative iPackageManagerNative = IPackageManagerNative.Stub.asInterface(
+                ServiceManager.getService("package_native"));
+        if (iPackageManagerNative == null) {
+            Slog.e(TAG, "IPackageManagerNative is null");
+            return;
+        }
+
+        try {
+            iPackageManagerNative.registerStagedApexObserver(new IStagedApexObserver.Stub() {
+                @Override
+                public void onApexStaged(ApexStagedEvent event) throws RemoteException {
+                    Slog.d(TAG, "A new APEX has been staged for update. There are currently "
+                            + event.stagedApexModuleNames.length + " APEX(s) staged for update. "
+                            + "Scheduling measurement...");
+                    UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
+                            BinaryTransparencyService.this);
+                }
+            });
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to register a StagedApexObserver.");
+        }
+    }
+
     private String translateContentDigestAlgorithmIdToString(int algorithmId) {
         switch (algorithmId) {
             case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index 86a0857..e21895a 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -21,7 +21,10 @@
 import static com.android.server.EventLogTags.IMF_HIDE_IME;
 import static com.android.server.EventLogTags.IMF_SHOW_IME;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;
 
 import android.annotation.Nullable;
 import android.os.Binder;
@@ -30,6 +33,7 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.inputmethod.InputMethodDebug;
@@ -124,6 +128,12 @@
     @Override
     public void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
             @ImeVisibilityStateComputer.VisibilityState int state) {
+        applyImeVisibility(windowToken, statsToken, state, -1 /* ignore reason */);
+    }
+
+    @GuardedBy("ImfLock.class")
+    void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+            @ImeVisibilityStateComputer.VisibilityState int state, int reason) {
         switch (state) {
             case STATE_SHOW_IME:
                 ImeTracker.get().onProgress(statsToken,
@@ -148,6 +158,17 @@
                             ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                 }
                 break;
+            case STATE_HIDE_IME_EXPLICIT:
+                mService.hideCurrentInputLocked(windowToken, statsToken, 0, null, reason);
+                break;
+            case STATE_HIDE_IME_NOT_ALWAYS:
+                mService.hideCurrentInputLocked(windowToken, statsToken,
+                        InputMethodManager.HIDE_NOT_ALWAYS, null, reason);
+                break;
+            case STATE_SHOW_IME_IMPLICIT:
+                mService.showCurrentInputLocked(windowToken, statsToken,
+                        InputMethodManager.SHOW_IMPLICIT, null, reason);
+                break;
             default:
                 throw new IllegalArgumentException("Invalid IME visibility state: " + state);
         }
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index a2655f4..795e4bf 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -18,11 +18,13 @@
 
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
 import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
+import static android.server.inputmethod.InputMethodManagerServiceProto.INPUT_SHOWN;
 import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_EXPLICITLY_REQUESTED;
 import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_FORCED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
 import static android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 
@@ -32,6 +34,7 @@
 import android.accessibilityservice.AccessibilityService;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.content.res.Configuration;
 import android.os.IBinder;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -42,6 +45,8 @@
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodManager;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.server.LocalServices;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -88,6 +93,11 @@
      */
     boolean mShowForced;
 
+    /**
+     * Set if we last told the input method to show itself.
+     */
+    private boolean mInputShown;
+
     /** Represent the invalid IME visibility state */
     public static final int STATE_INVALID = -1;
 
@@ -105,6 +115,12 @@
 
     /** State to handle showing an IME preview surface during the app was loosing the IME focus */
     public static final int STATE_SHOW_IME_SNAPSHOT = 4;
+
+    public static final int STATE_HIDE_IME_EXPLICIT = 5;
+
+    public static final int STATE_HIDE_IME_NOT_ALWAYS = 6;
+
+    public static final int STATE_SHOW_IME_IMPLICIT = 7;
     @IntDef({
             STATE_INVALID,
             STATE_HIDE_IME,
@@ -112,6 +128,9 @@
             STATE_SHOW_IME_ABOVE_OVERLAY,
             STATE_SHOW_IME_BEHIND_OVERLAY,
             STATE_SHOW_IME_SNAPSHOT,
+            STATE_HIDE_IME_EXPLICIT,
+            STATE_HIDE_IME_NOT_ALWAYS,
+            STATE_SHOW_IME_IMPLICIT,
     })
     @interface VisibilityState {}
 
@@ -120,11 +139,38 @@
      */
     private final ImeVisibilityPolicy mPolicy;
 
-    public ImeVisibilityStateComputer(InputMethodManagerService service) {
+    public ImeVisibilityStateComputer(@NonNull InputMethodManagerService service) {
+        this(service,
+                LocalServices.getService(WindowManagerInternal.class),
+                LocalServices.getService(WindowManagerInternal.class)::getDisplayImePolicy,
+                new ImeVisibilityPolicy());
+    }
+
+    @VisibleForTesting
+    public ImeVisibilityStateComputer(@NonNull InputMethodManagerService service,
+            @NonNull Injector injector) {
+        this(service, injector.getWmService(), injector.getImeValidator(),
+                new ImeVisibilityPolicy());
+    }
+
+    interface Injector {
+        default WindowManagerInternal getWmService() {
+            return null;
+        }
+
+        default InputMethodManagerService.ImeDisplayValidator getImeValidator() {
+            return null;
+        }
+    }
+
+    private ImeVisibilityStateComputer(InputMethodManagerService service,
+            WindowManagerInternal wmService,
+            InputMethodManagerService.ImeDisplayValidator imeDisplayValidator,
+            ImeVisibilityPolicy imePolicy) {
         mService = service;
-        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
-        mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
-        mPolicy = new ImeVisibilityPolicy();
+        mWindowManagerInternal = wmService;
+        mImeDisplayValidator = imeDisplayValidator;
+        mPolicy = imePolicy;
     }
 
     /**
@@ -187,6 +233,7 @@
     void clearImeShowFlags() {
         mRequestedShowExplicitly = false;
         mShowForced = false;
+        mInputShown = false;
     }
 
     int computeImeDisplayId(@NonNull ImeTargetWindowState state, int displayId) {
@@ -207,15 +254,22 @@
      *                            {@link #STATE_HIDE_IME}.
      */
     void requestImeVisibility(IBinder windowToken, boolean showIme) {
-        final ImeTargetWindowState state = getOrCreateWindowState(windowToken);
-        state.setRequestedImeVisible(showIme);
-        setWindowState(windowToken, state);
+        ImeTargetWindowState state = getOrCreateWindowState(windowToken);
+        if (!mPolicy.mPendingA11yRequestingHideKeyboard) {
+            state.setRequestedImeVisible(showIme);
+        } else {
+            // As A11y requests no IME is just a temporary, so we don't change the requested IME
+            // visible in case the last visibility state goes wrong after leaving from the a11y
+            // policy.
+            mPolicy.mPendingA11yRequestingHideKeyboard = false;
+        }
+        setWindowStateInner(windowToken, state);
     }
 
     ImeTargetWindowState getOrCreateWindowState(IBinder windowToken) {
         ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
         if (state == null) {
-            state = new ImeTargetWindowState(SOFT_INPUT_STATE_UNSPECIFIED, false, false);
+            state = new ImeTargetWindowState(SOFT_INPUT_STATE_UNSPECIFIED, 0, false, false, false);
         }
         return state;
     }
@@ -229,16 +283,176 @@
         ImeTargetWindowState state = getWindowStateOrNull(windowToken);
         if (state != null) {
             state.setRequestImeToken(token);
-            setWindowState(windowToken, state);
+            setWindowStateInner(windowToken, state);
         }
     }
 
-    void setWindowState(IBinder windowToken, ImeTargetWindowState newState) {
-        if (DEBUG) Slog.d(TAG, "setWindowState, windowToken=" + windowToken
+    void setWindowState(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
+        final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
+        if (state != null && newState.hasEdiorFocused()) {
+            // Inherit the last requested IME visible state when the target window is still
+            // focused with an editor.
+            newState.setRequestedImeVisible(state.mRequestedImeVisible);
+        }
+        setWindowStateInner(windowToken, newState);
+    }
+
+    private void setWindowStateInner(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
+        if (DEBUG) Slog.d(TAG, "setWindowStateInner, windowToken=" + windowToken
                 + ", state=" + newState);
         mRequestWindowStateMap.put(windowToken, newState);
     }
 
+    static class ImeVisibilityResult {
+        private final @VisibilityState int mState;
+        private final @SoftInputShowHideReason int mReason;
+
+        ImeVisibilityResult(@VisibilityState int state, @SoftInputShowHideReason int reason) {
+            mState = state;
+            mReason = reason;
+        }
+
+        @VisibilityState int getState() {
+            return mState;
+        }
+
+        @SoftInputShowHideReason int getReason() {
+            return mReason;
+        }
+    }
+
+    ImeVisibilityResult computeState(ImeTargetWindowState state, boolean allowVisible) {
+        // TODO: Output the request IME visibility state according to the requested window state
+        final int softInputVisibility = state.mSoftInputModeState & SOFT_INPUT_MASK_STATE;
+        // Should we auto-show the IME even if the caller has not
+        // specified what should be done with it?
+        // We only do this automatically if the window can resize
+        // to accommodate the IME (so what the user sees will give
+        // them good context without input information being obscured
+        // by the IME) or if running on a large screen where there
+        // is more room for the target window + IME.
+        final boolean doAutoShow =
+                (state.mSoftInputModeState & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+                        == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+                        || mService.mRes.getConfiguration().isLayoutSizeAtLeast(
+                        Configuration.SCREENLAYOUT_SIZE_LARGE);
+        final boolean isForwardNavigation = (state.mSoftInputModeState
+                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0;
+
+        // We shows the IME when the system allows the IME focused target window to restore the
+        // IME visibility (e.g. switching to the app task when last time the IME is visible).
+        // Note that we don't restore IME visibility for some cases (e.g. when the soft input
+        // state is ALWAYS_HIDDEN or STATE_HIDDEN with forward navigation).
+        // Because the app might leverage these flags to hide soft-keyboard with showing their own
+        // UI for input.
+        if (state.hasEdiorFocused() && shouldRestoreImeVisibility(state)) {
+            if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
+            // Inherit the last requested IME visible state when the target window is still
+            // focused with an editor.
+            state.setRequestedImeVisible(true);
+            setWindowStateInner(getWindowTokenFrom(state), state);
+            return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
+                    SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
+        }
+
+        switch (softInputVisibility) {
+            case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
+                if (state.hasImeFocusChanged() && (!state.hasEdiorFocused() || !doAutoShow)) {
+                    if (WindowManager.LayoutParams.mayUseInputMethod(state.getWindowFlags())) {
+                        // There is no focus view, and this window will
+                        // be behind any soft input window, so hide the
+                        // soft input window if it is shown.
+                        if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
+                        return new ImeVisibilityResult(STATE_HIDE_IME_NOT_ALWAYS,
+                                SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
+                    }
+                } else if (state.hasEdiorFocused() && doAutoShow && isForwardNavigation) {
+                    // There is a focus view, and we are navigating forward
+                    // into the window, so show the input window for the user.
+                    // We only do this automatically if the window can resize
+                    // to accommodate the IME (so what the user sees will give
+                    // them good context without input information being obscured
+                    // by the IME) or if running on a large screen where there
+                    // is more room for the target window + IME.
+                    if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
+                    return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
+                            SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV);
+                }
+                break;
+            case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+                // Do nothing.
+                break;
+            case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+                if (isForwardNavigation) {
+                    if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
+                    return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
+                            SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV);
+                }
+                break;
+            case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
+                if (state.hasImeFocusChanged()) {
+                    if (DEBUG) Slog.v(TAG, "Window asks to hide input");
+                    return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
+                            SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
+                }
+                break;
+            case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
+                if (isForwardNavigation) {
+                    if (allowVisible) {
+                        if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
+                        return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
+                                SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV);
+                    } else {
+                        Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
+                                + " there is no focused view that also returns true from"
+                                + " View#onCheckIsTextEditor()");
+                    }
+                }
+                break;
+            case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+                if (DEBUG) Slog.v(TAG, "Window asks to always show input");
+                if (allowVisible) {
+                    if (state.hasImeFocusChanged()) {
+                        return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
+                                SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
+                    }
+                } else {
+                    Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
+                            + " there is no focused view that also returns true from"
+                            + " View#onCheckIsTextEditor()");
+                }
+                break;
+        }
+
+        if (!state.hasImeFocusChanged()) {
+            // On previous platforms, when Dialogs re-gained focus, the Activity behind
+            // would briefly gain focus first, and dismiss the IME.
+            // On R that behavior has been fixed, but unfortunately apps have come
+            // to rely on this behavior to hide the IME when the editor no longer has focus
+            // To maintain compatibility, we are now hiding the IME when we don't have
+            // an editor upon refocusing a window.
+            if (state.isStartInputByGainFocus()) {
+                if (DEBUG) Slog.v(TAG, "Same window without editor will hide input");
+                return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
+                        SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
+            }
+        }
+        if (!state.hasEdiorFocused() && mInputShown && state.isStartInputByGainFocus()
+                && mService.mInputMethodDeviceConfigs.shouldHideImeWhenNoEditorFocus()) {
+            // Hide the soft-keyboard when the system do nothing for softInputModeState
+            // of the window being gained focus without an editor. This behavior benefits
+            // to resolve some unexpected IME visible cases while that window with following
+            // configurations being switched from an IME shown window:
+            // 1) SOFT_INPUT_STATE_UNCHANGED state without an editor
+            // 2) SOFT_INPUT_STATE_VISIBLE state without an editor
+            // 3) SOFT_INPUT_STATE_ALWAYS_VISIBLE state without an editor
+            if (DEBUG) Slog.v(TAG, "Window without editor will hide input");
+            return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
+                    SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR);
+        }
+        return null;
+    }
+
     IBinder getWindowTokenFrom(IBinder requestImeToken) {
         for (IBinder windowToken : mRequestWindowStateMap.keySet()) {
             final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
@@ -273,11 +487,20 @@
         return mWindowManagerInternal.shouldRestoreImeVisibility(getWindowTokenFrom(state));
     }
 
+    boolean isInputShown() {
+        return mInputShown;
+    }
+
+    void setInputShown(boolean inputShown) {
+        mInputShown = inputShown;
+    }
+
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
         proto.write(SHOW_EXPLICITLY_REQUESTED, mRequestedShowExplicitly);
         proto.write(SHOW_FORCED, mShowForced);
         proto.write(ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD,
                 mPolicy.isA11yRequestNoSoftKeyboard());
+        proto.write(INPUT_SHOWN, mInputShown);
     }
 
     void dump(PrintWriter pw) {
@@ -285,6 +508,7 @@
         p.println(" mRequestedShowExplicitly=" + mRequestedShowExplicitly
                 + " mShowForced=" + mShowForced);
         p.println("  mImeHiddenByDisplayPolicy=" + mPolicy.isImeHiddenByDisplayPolicy());
+        p.println("  mInputShown=" + mInputShown);
     }
 
     /**
@@ -309,6 +533,14 @@
          */
         private boolean mA11yRequestingNoSoftKeyboard;
 
+        /**
+         * Used when A11y request to hide IME temporary when receiving
+         * {@link AccessibilityService#SHOW_MODE_HIDDEN} from
+         * {@link android.provider.Settings.Secure#ACCESSIBILITY_SOFT_KEYBOARD_MODE} without
+         * changing the requested IME visible state.
+         */
+        private boolean mPendingA11yRequestingHideKeyboard;
+
         void setImeHiddenByDisplayPolicy(boolean hideIme) {
             mImeHiddenByDisplayPolicy = hideIme;
         }
@@ -320,6 +552,9 @@
         void setA11yRequestNoSoftKeyboard(int keyboardShowMode) {
             mA11yRequestingNoSoftKeyboard =
                     (keyboardShowMode & AccessibilityService.SHOW_MODE_MASK) == SHOW_MODE_HIDDEN;
+            if (mA11yRequestingNoSoftKeyboard) {
+                mPendingA11yRequestingHideKeyboard = true;
+            }
         }
 
         boolean isA11yRequestNoSoftKeyboard() {
@@ -335,11 +570,14 @@
      * A class that represents the current state of the IME target window.
      */
     static class ImeTargetWindowState {
-        ImeTargetWindowState(@SoftInputModeFlags int softInputModeState, boolean imeFocusChanged,
-                boolean hasFocusedEditor) {
+        ImeTargetWindowState(@SoftInputModeFlags int softInputModeState, int windowFlags,
+                boolean imeFocusChanged, boolean hasFocusedEditor,
+                boolean isStartInputByGainFocus) {
             mSoftInputModeState = softInputModeState;
+            mWindowFlags = windowFlags;
             mImeFocusChanged = imeFocusChanged;
             mHasFocusedEditor = hasFocusedEditor;
+            mIsStartInputByGainFocus = isStartInputByGainFocus;
         }
 
         /**
@@ -347,6 +585,8 @@
          */
         private final @SoftInputModeFlags int mSoftInputModeState;
 
+        private final int mWindowFlags;
+
         /**
          * {@code true} means the IME focus changed from the previous window, {@code false}
          * otherwise.
@@ -358,6 +598,8 @@
          */
         private final boolean mHasFocusedEditor;
 
+        private final boolean mIsStartInputByGainFocus;
+
         /**
          * Set if the client has asked for the input method to be shown.
          */
@@ -382,10 +624,18 @@
             return mHasFocusedEditor;
         }
 
+        boolean isStartInputByGainFocus() {
+            return mIsStartInputByGainFocus;
+        }
+
         int getSoftInputModeState() {
             return mSoftInputModeState;
         }
 
+        int getWindowFlags() {
+            return mWindowFlags;
+        }
+
         private void setImeDisplayId(int imeDisplayId) {
             mImeDisplayId = imeDisplayId;
         }
@@ -418,6 +668,7 @@
                     + " requestedImeVisible " + mRequestedImeVisible
                     + " imeDisplayId " + mImeDisplayId
                     + " softInputModeState " + softInputModeToString(mSoftInputModeState)
+                    + " isStartInputByGainFocus " + mIsStartInputByGainFocus
                     + "}";
         }
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 079234c..187de930 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -350,7 +350,7 @@
                     // should now try to restart the service for us.
                     mLastBindTime = SystemClock.uptimeMillis();
                     clearCurMethodAndSessions();
-                    mService.clearInputShowRequestLocked();
+                    mService.clearInputShownLocked();
                     mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
                 }
             }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2dbbb10..a94c90c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -33,13 +33,11 @@
 import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_TOKEN_DISPLAY_ID;
 import static android.server.inputmethod.InputMethodManagerServiceProto.HAVE_CONNECTION;
 import static android.server.inputmethod.InputMethodManagerServiceProto.IME_WINDOW_VISIBILITY;
-import static android.server.inputmethod.InputMethodManagerServiceProto.INPUT_SHOWN;
 import static android.server.inputmethod.InputMethodManagerServiceProto.IN_FULLSCREEN_MODE;
 import static android.server.inputmethod.InputMethodManagerServiceProto.IS_INTERACTIVE;
 import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_IME_TARGET_WINDOW_NAME;
 import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_SWITCH_USER_ID;
 import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_IME_WITH_HARD_KEYBOARD;
-import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_REQUESTED;
 import static android.server.inputmethod.InputMethodManagerServiceProto.SYSTEM_READY;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -47,6 +45,7 @@
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult;
 import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT;
 import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed;
 
@@ -77,7 +76,6 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Matrix;
@@ -624,16 +622,6 @@
         return mBindingController.hasConnection();
     }
 
-    /**
-     * Set if the client has asked for the input method to be shown.
-     */
-    private boolean mShowRequested;
-
-    /**
-     * Set if we last told the input method to show itself.
-     */
-    private boolean mInputShown;
-
     /** The token tracking the current IME request or {@code null} otherwise. */
     @Nullable
     private ImeTracker.Token mCurStatsToken;
@@ -689,7 +677,7 @@
      * The display ID of the input method indicates the fallback display which returned by
      * {@link #computeImeDisplayIdForTarget}.
      */
-    private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
+    static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
 
     /**
      * If non-null, this is the input method service we are currently connected
@@ -1174,12 +1162,10 @@
                     mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
                             accessibilitySoftKeyboardSetting);
                     if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
-                        final boolean showRequested = mShowRequested;
                         hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
                                 0 /* flags */, null /* resultReceiver */,
                                 SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE);
-                        mShowRequested = showRequested;
-                    } else if (mShowRequested) {
+                    } else if (isShowRequestedForCurrentWindow()) {
                         showCurrentInputImplicitLocked(mCurFocusedWindow,
                                 SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE);
                     }
@@ -2299,9 +2285,20 @@
     }
 
     @GuardedBy("ImfLock.class")
-    void clearInputShowRequestLocked() {
-        mShowRequested = mInputShown;
-        mInputShown = false;
+    void clearInputShownLocked() {
+        mVisibilityStateComputer.setInputShown(false);
+    }
+
+    @GuardedBy("ImfLock.class")
+    private boolean isInputShown() {
+        return mVisibilityStateComputer.isInputShown();
+    }
+
+    @GuardedBy("ImfLock.class")
+    private boolean isShowRequestedForCurrentWindow() {
+        final ImeTargetWindowState state = mVisibilityStateComputer.getWindowStateOrNull(
+                mCurFocusedWindow);
+        return state != null && state.isRequestedImeVisible();
     }
 
     @GuardedBy("ImfLock.class")
@@ -2340,7 +2337,7 @@
         setEnabledSessionLocked(session);
         session.mMethod.startInput(startInputToken, mCurInputConnection, mCurEditorInfo, restarting,
                 navButtonFlags, mCurImeDispatcher);
-        if (mShowRequested) {
+        if (isShowRequestedForCurrentWindow()) {
             if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
             // Re-use current statsToken, if it exists.
             final ImeTracker.Token statsToken = mCurStatsToken;
@@ -2559,7 +2556,7 @@
         if (!mPreventImeStartupUnlessTextEditor) {
             return false;
         }
-        if (mShowRequested) {
+        if (isShowRequestedForCurrentWindow()) {
             return false;
         }
         if (isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags)) {
@@ -3370,9 +3367,6 @@
                     ImeTracker.ORIGIN_SERVER_START_INPUT, reason);
         }
 
-        // TODO(b/246309664): make mShowRequested as per-window state.
-        mShowRequested = true;
-
         if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {
             return false;
         }
@@ -3398,8 +3392,7 @@
             }
             mVisibilityApplier.performShowIme(windowToken, statsToken,
                     mVisibilityStateComputer.getImeShowFlags(), resultReceiver, reason);
-            // TODO(b/246309664): make mInputShown tracked by the Ime visibility computer.
-            mInputShown = true;
+            mVisibilityStateComputer.setInputShown(true);
             return true;
         } else {
             ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
@@ -3417,7 +3410,7 @@
                 "InputMethodManagerService#hideSoftInput");
         synchronized (ImfLock.class) {
             if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) {
-                if (mInputShown) {
+                if (isInputShown()) {
                     ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
                 } else {
                     ImeTracker.get().onCancelled(statsToken,
@@ -3468,10 +3461,10 @@
         // application process as a valid request, and have even promised such a behavior with CTS
         // since Android Eclair.  That's why we need to accept IMM#hideSoftInput() even when only
         // IMMS#InputShown indicates that the software keyboard is shown.
-        // TODO(b/246309664): Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
+        // TODO(b/246309664): Clean up IMMS#mImeWindowVis
         IInputMethodInvoker curMethod = getCurMethodLocked();
-        final boolean shouldHideSoftInput = (curMethod != null)
-                && (mInputShown || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
+        final boolean shouldHideSoftInput = curMethod != null
+                && (isInputShown() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
 
         mVisibilityStateComputer.requestImeVisibility(windowToken, false);
         if (shouldHideSoftInput) {
@@ -3486,8 +3479,6 @@
         }
         mBindingController.setCurrentMethodNotVisible();
         mVisibilityStateComputer.clearImeShowFlags();
-        mInputShown = false;
-        mShowRequested = false;
         // Cancel existing statsToken for show IME as we got a hide request.
         ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
         mCurStatsToken = null;
@@ -3666,8 +3657,8 @@
 
         // Init the focused window state (e.g. whether the editor has focused or IME focus has
         // changed from another window).
-        final ImeTargetWindowState windowState = new ImeTargetWindowState(
-                softInputMode, !sameWindowFocused, isTextEditor);
+        final ImeTargetWindowState windowState = new ImeTargetWindowState(softInputMode,
+                windowFlags, !sameWindowFocused, isTextEditor, startInputByWinGainedFocus);
         mVisibilityStateComputer.setWindowState(windowToken, windowState);
 
         if (sameWindowFocused && isTextEditor) {
@@ -3692,74 +3683,21 @@
         mCurFocusedWindowClient = cs;
         mCurPerceptible = true;
 
-        // Should we auto-show the IME even if the caller has not
-        // specified what should be done with it?
-        // We only do this automatically if the window can resize
-        // to accommodate the IME (so what the user sees will give
-        // them good context without input information being obscured
-        // by the IME) or if running on a large screen where there
-        // is more room for the target window + IME.
-        final boolean doAutoShow =
-                (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
-                        == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
-                        || mRes.getConfiguration().isLayoutSizeAtLeast(
-                        Configuration.SCREENLAYOUT_SIZE_LARGE);
-
         // We want to start input before showing the IME, but after closing
         // it.  We want to do this after closing it to help the IME disappear
         // more quickly (not get stuck behind it initializing itself for the
         // new focused input, even if its window wants to hide the IME).
         boolean didStart = false;
-
         InputBindResult res = null;
-        // We show the IME when the system allows the IME focused target window to restore the
-        // IME visibility (e.g. switching to the app task when last time the IME is visible).
-        // Note that we don't restore IME visibility for some cases (e.g. when the soft input
-        // state is ALWAYS_HIDDEN or STATE_HIDDEN with forward navigation).
-        // Because the app might leverage these flags to hide soft-keyboard with showing their own
-        // UI for input.
-        if (isTextEditor && editorInfo != null
-                && mVisibilityStateComputer.shouldRestoreImeVisibility(windowState)) {
-            if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
-            res = startInputUncheckedLocked(cs, inputContext, remoteAccessibilityInputConnection,
-                    editorInfo, startInputFlags, startInputReason, unverifiedTargetSdkVersion,
-                    imeDispatcher);
-            showCurrentInputImplicitLocked(windowToken,
-                    SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
-            return res;
-        }
 
-        switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
-            case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
-                if (!sameWindowFocused && (!isTextEditor || !doAutoShow)) {
-                    if (LayoutParams.mayUseInputMethod(windowFlags)) {
-                        // There is no focus view, and this window will
-                        // be behind any soft input window, so hide the
-                        // soft input window if it is shown.
-                        if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
-                        hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
-                                InputMethodManager.HIDE_NOT_ALWAYS, null /* resultReceiver */,
-                                SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
-
-                        // If focused display changed, we should unbind current method
-                        // to make app window in previous display relayout after Ime
-                        // window token removed.
-                        // Note that we can trust client's display ID as long as it matches
-                        // to the display ID obtained from the window.
-                        if (cs.mSelfReportedDisplayId != mCurTokenDisplayId) {
-                            mBindingController.unbindCurrentMethod();
-                        }
-                    }
-                } else if (isTextEditor && doAutoShow
-                        && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                    // There is a focus view, and we are navigating forward
-                    // into the window, so show the input window for the user.
-                    // We only do this automatically if the window can resize
-                    // to accommodate the IME (so what the user sees will give
-                    // them good context without input information being obscured
-                    // by the IME) or if running on a large screen where there
-                    // is more room for the target window + IME.
-                    if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
+        final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.computeState(windowState,
+                isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags));
+        if (imeVisRes != null) {
+            switch (imeVisRes.getReason()) {
+                case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY:
+                case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV:
+                case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV:
+                case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE:
                     if (editorInfo != null) {
                         res = startInputUncheckedLocked(cs, inputContext,
                                 remoteAccessibilityInputConnection, editorInfo, startInputFlags,
@@ -3767,106 +3705,25 @@
                                 imeDispatcher);
                         didStart = true;
                     }
-                    showCurrentInputImplicitLocked(windowToken,
-                            SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV);
-                }
-                break;
-            case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
-                if (DEBUG) {
-                    Slog.v(TAG, "Window asks to keep the input in whatever state it was last in");
-                }
-                // Do nothing.
-                break;
-            case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
-                if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                    if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
-                    hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                            null /* resultReceiver */,
-                            SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV);
-                }
-                break;
-            case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
-                if (!sameWindowFocused) {
-                    if (DEBUG) Slog.v(TAG, "Window asks to hide input");
-                    hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                            null /* resultReceiver */,
-                            SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
-                }
-                break;
-            case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
-                if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                    if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
-                    if (isSoftInputModeStateVisibleAllowed(
-                            unverifiedTargetSdkVersion, startInputFlags)) {
-                        if (editorInfo != null) {
-                            res = startInputUncheckedLocked(cs, inputContext,
-                                    remoteAccessibilityInputConnection, editorInfo, startInputFlags,
-                                    startInputReason, unverifiedTargetSdkVersion,
-                                    imeDispatcher);
-                            didStart = true;
-                        }
-                        showCurrentInputImplicitLocked(windowToken,
-                                SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV);
-                    } else {
-                        Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
-                                + " there is no focused view that also returns true from"
-                                + " View#onCheckIsTextEditor()");
-                    }
-                }
-                break;
-            case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
-                if (DEBUG) Slog.v(TAG, "Window asks to always show input");
-                if (isSoftInputModeStateVisibleAllowed(
-                        unverifiedTargetSdkVersion, startInputFlags)) {
-                    if (!sameWindowFocused) {
-                        if (editorInfo != null) {
-                            res = startInputUncheckedLocked(cs, inputContext,
-                                    remoteAccessibilityInputConnection, editorInfo, startInputFlags,
-                                    startInputReason, unverifiedTargetSdkVersion,
-                                    imeDispatcher);
-                            didStart = true;
-                        }
-                        showCurrentInputImplicitLocked(windowToken,
-                                SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
-                    }
-                } else {
-                    Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
-                            + " there is no focused view that also returns true from"
-                            + " View#onCheckIsTextEditor()");
-                }
-                break;
-        }
+                    break;
+            }
 
+            mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null /* statsToken */,
+                    imeVisRes.getState(), imeVisRes.getReason());
+
+            if (imeVisRes.getReason() == SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW) {
+                // If focused display changed, we should unbind current method
+                // to make app window in previous display relayout after Ime
+                // window token removed.
+                // Note that we can trust client's display ID as long as it matches
+                // to the display ID obtained from the window.
+                if (cs.mSelfReportedDisplayId != mCurTokenDisplayId) {
+                    mBindingController.unbindCurrentMethod();
+                }
+            }
+        }
         if (!didStart) {
             if (editorInfo != null) {
-                if (sameWindowFocused) {
-                    // On previous platforms, when Dialogs re-gained focus, the Activity behind
-                    // would briefly gain focus first, and dismiss the IME.
-                    // On R that behavior has been fixed, but unfortunately apps have come
-                    // to rely on this behavior to hide the IME when the editor no longer has focus
-                    // To maintain compatibility, we are now hiding the IME when we don't have
-                    // an editor upon refocusing a window.
-                    if (startInputByWinGainedFocus) {
-                        if (DEBUG) Slog.v(TAG, "Same window without editor will hide input");
-                        hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
-                                0 /* flags */, null /* resultReceiver */,
-                                SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
-                    }
-                }
-                if (!isTextEditor && mInputShown && startInputByWinGainedFocus
-                        && mInputMethodDeviceConfigs.shouldHideImeWhenNoEditorFocus()) {
-                    // Hide the soft-keyboard when the system do nothing for softInputModeState
-                    // of the window being gained focus without an editor. This behavior benefits
-                    // to resolve some unexpected IME visible cases while that window with following
-                    // configurations being switched from an IME shown window:
-                    // 1) SOFT_INPUT_STATE_UNCHANGED state without an editor
-                    // 2) SOFT_INPUT_STATE_VISIBLE state without an editor
-                    // 3) SOFT_INPUT_STATE_ALWAYS_VISIBLE state without an editor
-                    if (DEBUG) Slog.v(TAG, "Window without editor will hide input");
-                    hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                            null /* resultReceiver */,
-                            SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR);
-                }
                 res = startInputUncheckedLocked(cs, inputContext,
                         remoteAccessibilityInputConnection, editorInfo, startInputFlags,
                         startInputReason, unverifiedTargetSdkVersion,
@@ -4639,9 +4496,7 @@
                 mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE);
             }
             proto.write(CUR_ID, getCurIdLocked());
-            proto.write(SHOW_REQUESTED, mShowRequested);
             mVisibilityStateComputer.dumpDebug(proto, fieldId);
-            proto.write(INPUT_SHOWN, mInputShown);
             proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
             proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
             proto.write(CUR_TOKEN_DISPLAY_ID, mCurTokenDisplayId);
@@ -4785,6 +4640,16 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
+    @VisibleForTesting
+    ImeVisibilityStateComputer getVisibilityStateComputer() {
+        return mVisibilityStateComputer;
+    }
+
+    @VisibleForTesting
+    ImeVisibilityApplier getVisibilityApplier() {
+        return mVisibilityApplier;
+    }
+
     @GuardedBy("ImfLock.class")
     void setEnabledSessionLocked(SessionState session) {
         if (mEnabledSession != session) {
@@ -4847,7 +4712,9 @@
                         // This is undocumented so far, but IMM#showInputMethodPicker() has been
                         // implemented so that auxiliary subtypes will be excluded when the soft
                         // keyboard is invisible.
-                        showAuxSubtypes = mInputShown;
+                        synchronized (ImfLock.class) {
+                            showAuxSubtypes = isInputShown();
+                        }
                         break;
                     case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
                         showAuxSubtypes = true;
@@ -4876,7 +4743,7 @@
                 synchronized (ImfLock.class) {
                     try {
                         if (mEnabledSession != null && mEnabledSession.mSession != null
-                                && !mShowRequested) {
+                                && !isShowRequestedForCurrentWindow()) {
                             mEnabledSession.mSession.removeImeSurface();
                         }
                     } catch (RemoteException e) {
@@ -5864,7 +5731,6 @@
             method = getCurMethodLocked();
             p.println("  mCurMethod=" + getCurMethodLocked());
             p.println("  mEnabledSession=" + mEnabledSession);
-            p.println("  mShowRequested=" + mShowRequested + " mInputShown=" + mInputShown);
             mVisibilityStateComputer.dump(pw);
             p.println("  mInFullscreenMode=" + mInFullscreenMode);
             p.println("  mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 71593e1..5e62b56 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -138,7 +138,7 @@
             this.activeApexChanged = activeApexChanged;
         }
 
-        private ActiveApexInfo(ApexInfo apexInfo) {
+        public ActiveApexInfo(ApexInfo apexInfo) {
             this(
                     apexInfo.moduleName,
                     new File(Environment.getApexDirectory() + File.separator
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 9785d47..f85d6af 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -405,11 +405,15 @@
                                     new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_PACKAGE_MANAGER);
                             tr.traceBegin("jobExecution");
                             boolean completed = false;
+                            boolean fatalError = false;
                             try {
                                 completed = runIdleOptimization(
                                         pm, pkgs, params.getJobId() == JOB_POST_BOOT_UPDATE);
                             } catch (LegacyDexoptDisabledException e) {
                                 Slog.wtf(TAG, e);
+                            } catch (RuntimeException e) {
+                                fatalError = true;
+                                throw e;
                             } finally { // Those cleanup should be done always.
                                 tr.traceEnd();
                                 Slog.i(TAG,
@@ -422,12 +426,10 @@
                                     if (completed) {
                                         markPostBootUpdateCompleted(params);
                                     }
-                                    // Reschedule when cancelled
-                                    job.jobFinished(params, !completed);
-                                } else {
-                                    // Periodic job
-                                    job.jobFinished(params, false /* reschedule */);
                                 }
+                                // Reschedule when cancelled. No need to reschedule when failed with
+                                // fatal error because it's likely to fail again.
+                                job.jobFinished(params, !completed && !fatalError);
                                 markDexOptCompleted();
                             }
                         }));
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index db3a343..69436da 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IBackgroundInstallControlService;
+import android.content.pm.InstallSourceInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -183,10 +184,12 @@
             return;
         }
 
-        String installerPackageName = null;
+        String installerPackageName;
+        String initiatingPackageName;
         try {
-            installerPackageName = mPackageManager
-                    .getInstallSourceInfo(packageName).getInstallingPackageName();
+            final InstallSourceInfo installInfo = mPackageManager.getInstallSourceInfo(packageName);
+            installerPackageName = installInfo.getInstallingPackageName();
+            initiatingPackageName = installInfo.getInitiatingPackageName();
         } catch (PackageManager.NameNotFoundException e) {
             Slog.w(TAG, "Package's installer not found " + packageName);
             return;
@@ -196,7 +199,8 @@
         final long installTimestamp = System.currentTimeMillis()
                 - (SystemClock.uptimeMillis() - appInfo.createTimestamp);
 
-        if (wasForegroundInstallation(installerPackageName, userId, installTimestamp)) {
+        if (installedByAdb(initiatingPackageName)
+                || wasForegroundInstallation(installerPackageName, userId, installTimestamp)) {
             return;
         }
 
@@ -205,6 +209,12 @@
         writeBackgroundInstalledPackagesToDisk();
     }
 
+    // ADB sets installerPackageName to null, this creates a loophole to bypass BIC which will be
+    // addressed with b/265203007
+    private boolean installedByAdb(String initiatingPackageName) {
+        return initiatingPackageName == null;
+    }
+
     private boolean wasForegroundInstallation(String installerPackageName,
             int userId, long installTimestamp) {
         TreeSet<BackgroundInstallControlService.ForegroundTimeFrame> foregroundTimeFrames =
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index cf447a7..9da319d 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -65,8 +65,8 @@
 import com.android.server.art.ArtManagerLocal;
 import com.android.server.art.DexUseManagerLocal;
 import com.android.server.art.model.ArtFlags;
-import com.android.server.art.model.OptimizeParams;
-import com.android.server.art.model.OptimizeResult;
+import com.android.server.art.model.DexoptParams;
+import com.android.server.art.model.DexoptResult;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.Installer.LegacyDexoptDisabledException;
 import com.android.server.pm.PackageDexOptimizer.DexOptResult;
@@ -502,7 +502,7 @@
      *     necessary to fall back to the legacy code paths.
      */
     private Optional<Integer> performDexOptWithArtService(DexoptOptions options,
-            /*@OptimizeFlags*/ int extraFlags) {
+            /*@DexoptFlags*/ int extraFlags) {
         ArtManagerLocal artManager = getArtManagerLocal();
         if (artManager == null) {
             return Optional.empty();
@@ -522,14 +522,14 @@
                 return Optional.of(PackageDexOptimizer.DEX_OPT_SKIPPED);
             }
 
-            OptimizeParams params = options.convertToOptimizeParams(extraFlags);
+            DexoptParams params = options.convertToDexoptParams(extraFlags);
             if (params == null) {
                 return Optional.empty();
             }
 
-            OptimizeResult result;
+            DexoptResult result;
             try {
-                result = artManager.optimizePackage(snapshot, options.getPackageName(), params);
+                result = artManager.dexoptPackage(snapshot, options.getPackageName(), params);
             } catch (UnsupportedOperationException e) {
                 reportArtManagerFallback(options.getPackageName(), e.toString());
                 return Optional.empty();
@@ -954,22 +954,21 @@
         }
     }
 
-    private static class OptimizePackageDoneHandler
-            implements ArtManagerLocal.OptimizePackageDoneCallback {
+    private static class DexoptDoneHandler implements ArtManagerLocal.DexoptDoneCallback {
         @NonNull private final PackageManagerService mPm;
 
-        OptimizePackageDoneHandler(@NonNull PackageManagerService pm) { mPm = pm; }
+        DexoptDoneHandler(@NonNull PackageManagerService pm) { mPm = pm; }
 
         /**
-         * Called after every package optimization operation done by {@link ArtManagerLocal}.
+         * Called after every package dexopt operation done by {@link ArtManagerLocal}.
          */
         @Override
-        public void onOptimizePackageDone(@NonNull OptimizeResult result) {
-            for (OptimizeResult.PackageOptimizeResult pkgRes : result.getPackageOptimizeResults()) {
+        public void onDexoptDone(@NonNull DexoptResult result) {
+            for (DexoptResult.PackageDexoptResult pkgRes : result.getPackageDexoptResults()) {
                 CompilerStats.PackageStats stats =
                         mPm.getOrCreateCompilerPackageStats(pkgRes.getPackageName());
-                for (OptimizeResult.DexContainerFileOptimizeResult dexRes :
-                        pkgRes.getDexContainerFileOptimizeResults()) {
+                for (DexoptResult.DexContainerFileDexoptResult dexRes :
+                        pkgRes.getDexContainerFileDexoptResults()) {
                     stats.setCompileTime(
                             dexRes.getDexContainerFile(), dexRes.getDex2oatWallTimeMillis());
                 }
@@ -994,13 +993,13 @@
         ArtManagerLocal artManager = new ArtManagerLocal(systemContext);
         // There doesn't appear to be any checks that @NonNull is heeded, so use requireNonNull
         // below to ensure we don't store away a null that we'll fail on later.
-        artManager.addOptimizePackageDoneCallback(false /* onlyIncludeUpdates */,
-                Runnable::run, new OptimizePackageDoneHandler(Objects.requireNonNull(pm)));
+        artManager.addDexoptDoneCallback(false /* onlyIncludeUpdates */,
+                Runnable::run, new DexoptDoneHandler(Objects.requireNonNull(pm)));
         LocalManagerRegistry.addManager(ArtManagerLocal.class, artManager);
     }
 
     /**
-     * Returns {@link ArtManagerLocal} if ART Service should be used for package optimization.
+     * Returns {@link ArtManagerLocal} if ART Service should be used for package dexopt.
      */
     private static @Nullable ArtManagerLocal getArtManagerLocal() {
         if (!useArtService()) {
@@ -1014,25 +1013,25 @@
     }
 
     /**
-     * Converts an ART Service {@link OptimizeResult} to {@link DexOptResult}.
+     * Converts an ART Service {@link DexoptResult} to {@link DexOptResult}.
      *
      * For interfacing {@link ArtManagerLocal} with legacy dex optimization code in PackageManager.
      */
     @DexOptResult
-    private static int convertToDexOptResult(OptimizeResult result) {
-        /*@OptimizeStatus*/ int status = result.getFinalStatus();
+    private static int convertToDexOptResult(DexoptResult result) {
+        /*@DexoptResultStatus*/ int status = result.getFinalStatus();
         switch (status) {
-            case OptimizeResult.OPTIMIZE_SKIPPED:
+            case DexoptResult.DEXOPT_SKIPPED:
                 return PackageDexOptimizer.DEX_OPT_SKIPPED;
-            case OptimizeResult.OPTIMIZE_FAILED:
+            case DexoptResult.DEXOPT_FAILED:
                 return PackageDexOptimizer.DEX_OPT_FAILED;
-            case OptimizeResult.OPTIMIZE_PERFORMED:
+            case DexoptResult.DEXOPT_PERFORMED:
                 return PackageDexOptimizer.DEX_OPT_PERFORMED;
-            case OptimizeResult.OPTIMIZE_CANCELLED:
+            case DexoptResult.DEXOPT_CANCELLED:
                 return PackageDexOptimizer.DEX_OPT_CANCELLED;
             default:
-                throw new IllegalArgumentException("OptimizeResult for "
-                        + result.getPackageOptimizeResults().get(0).getPackageName()
+                throw new IllegalArgumentException("DexoptResult for "
+                        + result.getPackageDexoptResults().get(0).getPackageName()
                         + " has unsupported status " + status);
         }
     }
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index 3385a09..fcaaa90 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -111,6 +111,8 @@
                 dumpState.setOptionEnabled(DumpState.OPTION_DUMP_ALL_COMPONENTS);
             } else if ("-f".equals(opt)) {
                 dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
+            } else if ("--include-apex".equals(opt)) {
+                dumpState.setOptionEnabled(DumpState.OPTION_INCLUDE_APEX);
             } else if ("--proto".equals(opt)) {
                 dumpProto(snapshot, fd);
                 return;
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
index 6225753..0bdce21 100644
--- a/services/core/java/com/android/server/pm/DumpState.java
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -51,6 +51,7 @@
     public static final int OPTION_SHOW_FILTERS = 1 << 0;
     public static final int OPTION_DUMP_ALL_COMPONENTS = 1 << 1;
     public static final int OPTION_SKIP_PERMISSIONS = 1 << 2;
+    public static final int OPTION_INCLUDE_APEX = 1 << 3;
 
     private int mTypes;
 
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 6825dd7..5c4447e 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -21,11 +21,9 @@
 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
-import static com.android.server.pm.PackageManagerService.SCAN_AS_FACTORY;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
 import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
-import static com.android.server.pm.PackageManagerService.SCAN_DROP_CACHE;
 import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
 import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
@@ -147,14 +145,7 @@
                     sp.getFolder().getAbsolutePath())
                     || apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
                     sp.getFolder().getAbsolutePath() + File.separator)) {
-                int additionalScanFlag = SCAN_AS_APK_IN_APEX;
-                if (apexInfo.isFactory) {
-                    additionalScanFlag |= SCAN_AS_FACTORY;
-                }
-                if (apexInfo.activeApexChanged) {
-                    additionalScanFlag |= SCAN_DROP_CACHE;
-                }
-                return new ScanPartition(apexInfo.apexDirectory, sp, additionalScanFlag);
+                return new ScanPartition(apexInfo.apexDirectory, sp, apexInfo);
             }
         }
         return null;
@@ -266,7 +257,7 @@
         }
 
         scanDirTracedLI(mPm.getAppInstallDir(), 0,
-                mScanFlags | SCAN_REQUIRE_KNOWN, packageParser, mExecutorService);
+                mScanFlags | SCAN_REQUIRE_KNOWN, packageParser, mExecutorService, null);
 
         List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
         if (!unfinishedTasks.isEmpty()) {
@@ -335,12 +326,12 @@
             }
             scanDirTracedLI(partition.getOverlayFolder(),
                     mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
-                    packageParser, executorService);
+                    packageParser, executorService, partition.apexInfo);
         }
 
         scanDirTracedLI(frameworkDir,
                 mSystemParseFlags, mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
-                packageParser, executorService);
+                packageParser, executorService, null);
         if (!mPm.mPackages.containsKey("android")) {
             throw new IllegalStateException(
                     "Failed to load frameworks package; check log for warnings");
@@ -352,11 +343,11 @@
                 scanDirTracedLI(partition.getPrivAppFolder(),
                         mSystemParseFlags,
                         mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
-                        packageParser, executorService);
+                        packageParser, executorService, partition.apexInfo);
             }
             scanDirTracedLI(partition.getAppFolder(),
                     mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
-                    packageParser, executorService);
+                    packageParser, executorService, partition.apexInfo);
         }
     }
 
@@ -373,7 +364,8 @@
 
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,
-            PackageParser2 packageParser, ExecutorService executorService) {
+            PackageParser2 packageParser, ExecutorService executorService,
+            @Nullable ApexManager.ActiveApexInfo apexInfo) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
         try {
             if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
@@ -381,7 +373,7 @@
                 parseFlags |= PARSE_APK_IN_APEX;
             }
             mInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags,
-                    scanFlags, packageParser, executorService);
+                    scanFlags, packageParser, executorService, apexInfo);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
index ced547c..9cf9122 100644
--- a/services/core/java/com/android/server/pm/InstallArgs.java
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -59,7 +59,7 @@
     final boolean mForceQueryableOverride;
     final int mDataLoaderType;
     final int mPackageSource;
-    final boolean mKeepApplicationEnabledSetting;
+    final boolean mApplicationEnabledSettingPersistent;
 
     // The list of instruction sets supported by this app. This is currently
     // only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -74,7 +74,7 @@
             int autoRevokePermissionsMode, String traceMethod, int traceCookie,
             SigningDetails signingDetails, int installReason, int installScenario,
             boolean forceQueryableOverride, int dataLoaderType, int packageSource,
-            boolean keepApplicationEnabledSetting) {
+            boolean applicationEnabledSettingPersistent) {
         mOriginInfo = originInfo;
         mMoveInfo = moveInfo;
         mInstallFlags = installFlags;
@@ -95,7 +95,7 @@
         mForceQueryableOverride = forceQueryableOverride;
         mDataLoaderType = dataLoaderType;
         mPackageSource = packageSource;
-        mKeepApplicationEnabledSetting = keepApplicationEnabledSetting;
+        mApplicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 28a074b..f0f23cd 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -367,10 +367,11 @@
 
         if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
             boolean isFactory = (scanFlags & SCAN_AS_FACTORY) != 0;
-            pkgSetting.getPkgState().setApkInApex(true);
             pkgSetting.getPkgState().setApkInUpdatedApex(!isFactory);
         }
 
+        pkgSetting.getPkgState().setApexModuleName(request.getApexModuleName());
+
         // TODO(toddke): Consider a method specifically for modifying the Package object
         // post scan; or, moving this stuff out of the Package object since it has nothing
         // to do with the package on disk.
@@ -1716,6 +1717,7 @@
                                 + ", old=" + oldPackage);
                     }
                     request.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+                    request.setApexModuleName(oldPackageState.getApexModuleName());
                     targetParseFlags = systemParseFlags;
                     targetScanFlags = systemScanFlags;
                 } else { // non system replace
@@ -2127,7 +2129,7 @@
                     }
                     // Enable system package for requested users
                     if (installedForUsers != null
-                            && !installRequest.isKeepApplicationEnabledSetting()) {
+                            && !installRequest.isApplicationEnabledSettingPersistent()) {
                         for (int origUserId : installedForUsers) {
                             if (userId == UserHandle.USER_ALL || userId == origUserId) {
                                 ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
@@ -2180,7 +2182,7 @@
                     // be installed and enabled. The caller, however, can explicitly specify to
                     // keep the existing enabled state.
                     ps.setInstalled(true, userId);
-                    if (!installRequest.isKeepApplicationEnabledSetting()) {
+                    if (!installRequest.isApplicationEnabledSettingPersistent()) {
                         ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId,
                                 installerPackageName);
                     }
@@ -2189,7 +2191,7 @@
                     // Thus, updating the settings to install the app for all users.
                     for (int currentUserId : allUsers) {
                         ps.setInstalled(true, currentUserId);
-                        if (!installRequest.isKeepApplicationEnabledSetting()) {
+                        if (!installRequest.isApplicationEnabledSettingPersistent()) {
                             ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId,
                                     installerPackageName);
                         }
@@ -3172,7 +3174,7 @@
         final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
         removePackageHelper.removePackage(stubPkg, true /*chatty*/);
         try {
-            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags);
+            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
                     e);
@@ -3304,7 +3306,7 @@
                         | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
         @PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
         final AndroidPackage pkg = scanSystemPackageTracedLI(
-                codePath, parseFlags, scanFlags);
+                codePath, parseFlags, scanFlags, null);
 
         synchronized (mPm.mLock) {
             PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3484,7 +3486,7 @@
                 try {
                     final File codePath = new File(pkg.getPath());
                     synchronized (mPm.mInstallLock) {
-                        scanSystemPackageTracedLI(codePath, 0, scanFlags);
+                        scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
                     }
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -3563,7 +3565,8 @@
 
             if (throwable == null) {
                 try {
-                    addForInitLI(parseResult.parsedPackage, newParseFlags, newScanFlags, null);
+                    addForInitLI(parseResult.parsedPackage, newParseFlags, newScanFlags, null,
+                            new ApexManager.ActiveApexInfo(ai));
                     AndroidPackage pkg = parseResult.parsedPackage.hideAsFinal();
                     if (ai.isFactory && !ai.isActive) {
                         disableSystemPackageLPw(pkg);
@@ -3585,8 +3588,8 @@
 
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     public void installPackagesFromDir(File scanDir, int parseFlags,
-            int scanFlags, PackageParser2 packageParser,
-            ExecutorService executorService) {
+            int scanFlags, PackageParser2 packageParser, ExecutorService executorService,
+            @Nullable ApexManager.ActiveApexInfo apexInfo) {
         final File[] files = scanDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
             Log.d(TAG, "No files in app dir " + scanDir);
@@ -3634,7 +3637,7 @@
                 }
                 try {
                     addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
-                            new UserHandle(UserHandle.USER_SYSTEM));
+                            new UserHandle(UserHandle.USER_SYSTEM), apexInfo);
                 } catch (PackageManagerException e) {
                     errorCode = e.error;
                     errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
@@ -3697,7 +3700,7 @@
             try {
                 synchronized (mPm.mInstallLock) {
                     final AndroidPackage newPkg = scanSystemPackageTracedLI(
-                            scanFile, reparseFlags, rescanFlags);
+                            scanFile, reparseFlags, rescanFlags, null);
                     // We rescanned a stub, add it to the list of stubbed system packages
                     if (newPkg.isStub()) {
                         stubSystemApps.add(packageName);
@@ -3716,10 +3719,11 @@
      */
     @GuardedBy("mPm.mInstallLock")
     public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
-            int scanFlags) throws PackageManagerException {
+            int scanFlags, @Nullable ApexManager.ActiveApexInfo apexInfo)
+            throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
         try {
-            return scanSystemPackageLI(scanFile, parseFlags, scanFlags);
+            return scanSystemPackageLI(scanFile, parseFlags, scanFlags, apexInfo);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -3730,7 +3734,8 @@
      *  Returns {@code null} in case of errors and the error code is stored in mLastScanError
      */
     @GuardedBy("mPm.mInstallLock")
-    private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags)
+    private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
+            @Nullable ApexManager.ActiveApexInfo apexInfo)
             throws PackageManagerException {
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
 
@@ -3748,7 +3753,7 @@
         }
 
         return addForInitLI(parsedPackage, parseFlags, scanFlags,
-                new UserHandle(UserHandle.USER_SYSTEM));
+                new UserHandle(UserHandle.USER_SYSTEM), apexInfo);
     }
 
     /**
@@ -3768,7 +3773,26 @@
     private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
             @ParsingPackageUtils.ParseFlags int parseFlags,
             @PackageManagerService.ScanFlags int scanFlags,
-            @Nullable UserHandle user) throws PackageManagerException {
+            @Nullable UserHandle user, @Nullable ApexManager.ActiveApexInfo activeApexInfo)
+            throws PackageManagerException {
+        PackageSetting disabledPkgSetting;
+        synchronized (mPm.mLock) {
+            disabledPkgSetting =
+                    mPm.mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName());
+            if (activeApexInfo != null && disabledPkgSetting != null) {
+                // When a disabled system package is scanned, its final PackageSetting is actually
+                // skipped and not added to any data structures, instead relying on the disabled
+                // setting read from the persisted Settings XML file. This persistence does not
+                // include the APEX module name, so here, re-set it from the active APEX info.
+                //
+                // This also has the (beneficial) side effect where if a package disappears from an
+                // APEX, leaving only a /data copy, it will lose its apexModuleName.
+                //
+                // This must be done before scanSystemPackageLI as that will throw in the case of a
+                // system -> data package.
+                disabledPkgSetting.setApexModuleName(activeApexInfo.apexModuleName);
+            }
+        }
 
         final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
                 parsedPackage, parseFlags, scanFlags, user);
@@ -3777,6 +3801,24 @@
         final InstallRequest installRequest = new InstallRequest(
                 parsedPackage, parseFlags, scanFlags, user, scanResult);
 
+        String existingApexModuleName = null;
+        synchronized (mPm.mLock) {
+            var existingPkgSetting = mPm.mSettings.getPackageLPr(parsedPackage.getPackageName());
+            if (existingPkgSetting != null) {
+                existingApexModuleName = existingPkgSetting.getApexModuleName();
+            }
+        }
+
+        if (activeApexInfo != null) {
+            installRequest.setApexModuleName(activeApexInfo.apexModuleName);
+        } else {
+            if (disabledPkgSetting != null) {
+                installRequest.setApexModuleName(disabledPkgSetting.getApexModuleName());
+            } else if (existingApexModuleName != null) {
+                installRequest.setApexModuleName(existingApexModuleName);
+            }
+        }
+
         synchronized (mPm.mLock) {
             boolean appIdCreated = false;
             try {
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 878c1c1..a9c5773 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -44,6 +44,7 @@
 
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
@@ -107,6 +108,12 @@
     @Nullable
     private ApexInfo mApexInfo;
 
+    /**
+     * For tracking {@link PackageState#getApexModuleName()}.
+     */
+    @Nullable
+    private String mApexModuleName;
+
     @Nullable
     private ScanResult mScanResult;
 
@@ -129,7 +136,7 @@
                 params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
                 params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
                 params.mDataLoaderType, params.mPackageSource,
-                params.mKeepApplicationEnabledSetting);
+                params.mApplicationEnabledSettingPersistent);
         mPackageMetrics = new PackageMetrics(this);
         mIsInstallInherit = params.mIsInherit;
         mSessionId = params.mSessionId;
@@ -348,6 +355,11 @@
     }
 
     @Nullable
+    public String getApexModuleName() {
+        return mApexModuleName;
+    }
+
+    @Nullable
     public String getSourceInstallerPackageName() {
         return mInstallArgs.mInstallSource.mInstallerPackageName;
     }
@@ -499,8 +511,8 @@
         return mScanResult.mChangedAbiCodePath;
     }
 
-    public boolean isKeepApplicationEnabledSetting() {
-        return mInstallArgs == null ? false : mInstallArgs.mKeepApplicationEnabledSetting;
+    public boolean isApplicationEnabledSettingPersistent() {
+        return mInstallArgs == null ? false : mInstallArgs.mApplicationEnabledSettingPersistent;
     }
 
     public boolean isForceQueryableOverride() {
@@ -644,6 +656,10 @@
         mApexInfo = apexInfo;
     }
 
+    public void setApexModuleName(@Nullable String apexModuleName) {
+        mApexModuleName = apexModuleName;
+    }
+
     public void setPkg(AndroidPackage pkg) {
         mPkg = pkg;
     }
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 439b5425..7b759e3 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -97,7 +97,7 @@
     final boolean mIsInherit;
     final int mSessionId;
     final int mRequireUserAction;
-    final boolean mKeepApplicationEnabledSetting;
+    final boolean mApplicationEnabledSettingPersistent;
 
     // For move install
     InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
@@ -130,7 +130,7 @@
         mIsInherit = false;
         mSessionId = -1;
         mRequireUserAction = USER_ACTION_UNSPECIFIED;
-        mKeepApplicationEnabledSetting = false;
+        mApplicationEnabledSettingPersistent = false;
     }
 
     InstallingSession(int sessionId, File stagedDir, IPackageInstallObserver2 observer,
@@ -164,7 +164,7 @@
         mIsInherit = sessionParams.mode == MODE_INHERIT_EXISTING;
         mSessionId = sessionId;
         mRequireUserAction = sessionParams.requireUserAction;
-        mKeepApplicationEnabledSetting = sessionParams.keepApplicationEnabledSetting;
+        mApplicationEnabledSettingPersistent = sessionParams.applicationEnabledSettingPersistent;
     }
 
     @Override
@@ -609,6 +609,7 @@
                 // processApkInstallRequests() fails. Need a way to keep info stored in apexd
                 // and PMS in sync in the face of install failures.
                 request.setApexInfo(apexInfo);
+                request.setApexModuleName(apexInfo.moduleName);
                 mPm.mHandler.post(() -> processApkInstallRequests(true, requests));
                 return;
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 350f5ef..47e18f1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -278,8 +278,8 @@
     private static final String ATTR_SIGNATURE = "signature";
     private static final String ATTR_CHECKSUM_KIND = "checksumKind";
     private static final String ATTR_CHECKSUM_VALUE = "checksumValue";
-    private static final String ATTR_KEEP_APPLICATION_ENABLED_SETTING =
-            "keepApplicationEnabledSetting";
+    private static final String ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT =
+            "applicationEnabledSettingPersistent";
 
     private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
     private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
@@ -1163,7 +1163,7 @@
             info.requireUserAction = params.requireUserAction;
             info.installerUid = mInstallerUid;
             info.packageSource = params.packageSource;
-            info.keepApplicationEnabledSetting = params.keepApplicationEnabledSetting;
+            info.applicationEnabledSettingPersistent = params.applicationEnabledSettingPersistent;
             info.pendingUserActionReason = userActionRequirementToReason(mUserActionRequirement);
         }
         return info;
@@ -4553,8 +4553,8 @@
     }
 
     @Override
-    public boolean isKeepApplicationEnabledSetting() {
-        return params.keepApplicationEnabledSetting;
+    public boolean isApplicationEnabledSettingPersistent() {
+        return params.applicationEnabledSettingPersistent;
     }
 
     @Override
@@ -4945,8 +4945,8 @@
             writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
             writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
             out.attributeInt(null, ATTR_INSTALL_REASON, params.installReason);
-            writeBooleanAttribute(out, ATTR_KEEP_APPLICATION_ENABLED_SETTING,
-                    params.keepApplicationEnabledSetting);
+            writeBooleanAttribute(out, ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT,
+                    params.applicationEnabledSettingPersistent);
 
             final boolean isDataLoader = params.dataLoaderParams != null;
             writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
@@ -5110,8 +5110,8 @@
         params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
         params.installReason = in.getAttributeInt(null, ATTR_INSTALL_REASON);
         params.packageSource = in.getAttributeInt(null, ATTR_PACKAGE_SOURCE);
-        params.keepApplicationEnabledSetting = in.getAttributeBoolean(null,
-                ATTR_KEEP_APPLICATION_ENABLED_SETTING, false);
+        params.applicationEnabledSettingPersistent = in.getAttributeBoolean(null,
+                ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT, false);
 
         if (in.getAttributeBoolean(null, ATTR_IS_DATALOADER, false)) {
             params.dataLoaderParams = new DataLoaderParams(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 92bbb7e..9cc0334 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -716,7 +716,7 @@
      * The list of all system partitions that may contain packages in ascending order of
      * specificity (the more generic, the earlier in the list a partition appears).
      */
-    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
     public static final List<ScanPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
             PackagePartitions.getOrderedPartitions(ScanPartition::new));
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 849cbeb..12841a4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3291,7 +3291,7 @@
                     sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
                     break;
                 case "--skip-enable":
-                    sessionParams.setKeepApplicationEnabledSetting();
+                    sessionParams.setApplicationEnabledSettingPersistent();
                     break;
                 case "--bypass-low-target-sdk-block":
                     sessionParams.installFlags |=
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 6562de96..53fdfaa 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -1262,6 +1262,12 @@
         return pkgState.isApkInUpdatedApex();
     }
 
+    @Nullable
+    @Override
+    public String getApexModuleName() {
+        return pkgState.getApexModuleName();
+    }
+
     public PackageSetting setDomainSetId(@NonNull UUID domainSetId) {
         mDomainSetId = domainSetId;
         onChanged();
@@ -1317,6 +1323,11 @@
         return this;
     }
 
+    public PackageSetting setApexModuleName(@Nullable String apexModuleName) {
+        pkgState.setApexModuleName(apexModuleName);
+        return this;
+    }
+
     @NonNull
     @Override
     public PackageStateUnserialized getTransientState() {
diff --git a/services/core/java/com/android/server/pm/ScanPartition.java b/services/core/java/com/android/server/pm/ScanPartition.java
index e1d2b3b..9ee6035 100644
--- a/services/core/java/com/android/server/pm/ScanPartition.java
+++ b/services/core/java/com/android/server/pm/ScanPartition.java
@@ -16,13 +16,17 @@
 
 package com.android.server.pm;
 
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FACTORY;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT;
 import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR;
+import static com.android.server.pm.PackageManagerService.SCAN_DROP_CACHE;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.PackagePartitions;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -32,14 +36,18 @@
 /**
  * List of partitions to be scanned during system boot
  */
-@VisibleForTesting
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
 public class ScanPartition extends PackagePartitions.SystemPartition {
     @PackageManagerService.ScanFlags
     public final int scanFlag;
 
+    @Nullable
+    public final ApexManager.ActiveApexInfo apexInfo;
+
     public ScanPartition(@NonNull PackagePartitions.SystemPartition partition) {
         super(partition);
         scanFlag = scanFlagForPartition(partition);
+        apexInfo = null;
     }
 
     /**
@@ -48,9 +56,21 @@
      * partition along with any specified additional scan flags.
      */
     public ScanPartition(@NonNull File folder, @NonNull ScanPartition original,
-            @PackageManagerService.ScanFlags int additionalScanFlag) {
+            @Nullable ApexManager.ActiveApexInfo apexInfo) {
         super(folder, original);
-        this.scanFlag = original.scanFlag | additionalScanFlag;
+        var scanFlags = original.scanFlag;
+        this.apexInfo = apexInfo;
+        if (apexInfo != null) {
+            scanFlags |= SCAN_AS_APK_IN_APEX;
+            if (apexInfo.isFactory) {
+                scanFlags |= SCAN_AS_FACTORY;
+            }
+            if (apexInfo.activeApexChanged) {
+                scanFlags |= SCAN_DROP_CACHE;
+            }
+        }
+        //noinspection WrongConstant
+        this.scanFlag = scanFlags;
     }
 
     private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 97fb0c2..aedf782 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5052,6 +5052,7 @@
         pw.print(prefix); pw.print("  privatePkgFlags="); printFlags(pw, ps.getPrivateFlags(),
                 PRIVATE_FLAG_DUMP_SPEC);
         pw.println();
+        pw.print(prefix); pw.print("  apexModuleName="); pw.println(ps.getApexModuleName());
 
         if (pkg != null && pkg.getOverlayTarget() != null) {
             pw.print(prefix); pw.print("  overlayTarget="); pw.println(pkg.getOverlayTarget());
@@ -5263,7 +5264,8 @@
                     && !packageName.equals(ps.getPackageName())) {
                 continue;
             }
-            if (ps.getPkg() != null && ps.getPkg().isApex()) {
+            if (ps.getPkg() != null && ps.getPkg().isApex()
+                    && !dumpState.isOptionEnabled(DumpState.OPTION_INCLUDE_APEX)) {
                 // Filter APEX packages which will be dumped in the APEX section
                 continue;
             }
@@ -5319,7 +5321,8 @@
                         && !packageName.equals(ps.getPackageName())) {
                     continue;
                 }
-                if (ps.getPkg() != null && ps.getPkg().isApex()) {
+                if (ps.getPkg() != null && ps.getPkg().isApex()
+                        && !dumpState.isOptionEnabled(DumpState.OPTION_INCLUDE_APEX)) {
                     // Filter APEX packages which will be dumped in the APEX section
                     continue;
                 }
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 4f7c2bd..23156d1 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -158,7 +158,7 @@
                 final AndroidPackage pkg;
                 try {
                     pkg = installPackageHelper.scanSystemPackageTracedLI(
-                            ps.getPath(), parseFlags, SCAN_INITIAL);
+                            ps.getPath(), parseFlags, SCAN_INITIAL, null);
                     loaded.add(pkg);
 
                 } catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index 411c19f..d3fba7c 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -24,7 +24,7 @@
 
 import com.android.server.art.ReasonMapping;
 import com.android.server.art.model.ArtFlags;
-import com.android.server.art.model.OptimizeParams;
+import com.android.server.art.model.DexoptParams;
 import com.android.server.pm.DexOptHelper;
 import com.android.server.pm.PackageManagerService;
 
@@ -201,22 +201,22 @@
     }
 
     /**
-     * Returns an {@link OptimizeParams} instance corresponding to this object, for use with
+     * Returns an {@link DexoptParams} instance corresponding to this object, for use with
      * {@link com.android.server.art.ArtManagerLocal}.
      *
-     * @param extraFlags extra {@link ArtFlags#OptimizeFlags} to set in the returned
-     *     {@code OptimizeParams} beyond those converted from this object
+     * @param extraFlags extra {@link ArtFlags#DexoptFlags} to set in the returned
+     *     {@code DexoptParams} beyond those converted from this object
      * @return null if the settings cannot be accurately represented, and hence the old
      *     PackageManager/installd code paths need to be used.
      */
-    public @Nullable OptimizeParams convertToOptimizeParams(/*@OptimizeFlags*/ int extraFlags) {
+    public @Nullable DexoptParams convertToDexoptParams(/*@DexoptFlags*/ int extraFlags) {
         if (mSplitName != null) {
             DexOptHelper.reportArtManagerFallback(
                     mPackageName, "Request to optimize only split " + mSplitName);
             return null;
         }
 
-        /*@OptimizeFlags*/ int flags = extraFlags;
+        /*@DexoptFlags*/ int flags = extraFlags;
         if ((mFlags & DEXOPT_CHECK_FOR_PROFILES_UPDATES) == 0
                 && isProfileGuidedCompilerFilter(mCompilerFilter)) {
             // ART Service doesn't support bypassing the profile update check when profiles are
@@ -322,7 +322,7 @@
                         "Invalid compilation reason " + mCompilationReason);
         }
 
-        return new OptimizeParams.Builder(reason, flags)
+        return new DexoptParams.Builder(reason, flags)
                 .setCompilerFilter(mCompilerFilter)
                 .setPriorityClass(priority)
                 .build();
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 5fdead0..a12c9d0 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -417,4 +417,11 @@
      * @hide
      */
     boolean isVendor();
+
+    /**
+     * The name of the APEX module containing this package, if it is an APEX or APK-in-APEX.
+     * @hide
+     */
+    @Nullable
+    String getApexModuleName();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index 8dee8ee..bc6dab4 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -154,6 +154,8 @@
     private final SigningInfo mSigningInfo;
     @NonNull
     private final SparseArray<PackageUserState> mUserStates;
+    @Nullable
+    private final String mApexModuleName;
 
     private PackageStateImpl(@NonNull PackageState pkgState, @Nullable AndroidPackage pkg) {
         mAndroidPackage = pkg;
@@ -206,6 +208,8 @@
             mUserStates.put(userStates.keyAt(index),
                     UserStateImpl.copy(userStates.valueAt(index)));
         }
+
+        mApexModuleName = pkgState.getApexModuleName();
     }
 
     @NonNull
@@ -714,6 +718,11 @@
     }
 
     @DataClass.Generated.Member
+    public @Nullable String getApexModuleName() {
+        return mApexModuleName;
+    }
+
+    @DataClass.Generated.Member
     public @NonNull PackageStateImpl setBooleans( int value) {
         mBooleans = value;
         return this;
@@ -723,7 +732,7 @@
             time = 1671671043929L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
-            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackage mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy int mHiddenApiEnforcementPolicy\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSeInfo\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibrary> mUsesLibraries\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override boolean isApex()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nprivate static final  int APK_IN_UPDATED_APEX\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackage mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy int mHiddenApiEnforcementPolicy\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSeInfo\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibrary> mUsesLibraries\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\nprivate final @android.annotation.Nullable java.lang.String mApexModuleName\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override boolean isApex()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nprivate static final  int APK_IN_UPDATED_APEX\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index 57fbfe9..19c0886 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -54,7 +54,6 @@
     private List<String> usesLibraryFiles = emptyList();
 
     private boolean updatedSystemApp;
-    private boolean apkInApex;
     private boolean apkInUpdatedApex;
 
     @NonNull
@@ -70,6 +69,9 @@
     @NonNull
     private final PackageSetting mPackageSetting;
 
+    @Nullable
+    private String mApexModuleName;
+
     public PackageStateUnserialized(@NonNull PackageSetting packageSetting) {
         mPackageSetting = packageSetting;
     }
@@ -138,11 +140,11 @@
         }
 
         this.updatedSystemApp = other.updatedSystemApp;
-        this.apkInApex = other.apkInApex;
         this.apkInUpdatedApex = other.apkInUpdatedApex;
         this.lastPackageUsageTimeInMills = other.lastPackageUsageTimeInMills;
         this.overrideSeInfo = other.overrideSeInfo;
         this.seInfo = other.seInfo;
+        this.mApexModuleName = other.mApexModuleName;
         mPackageSetting.onChanged();
     }
 
@@ -187,12 +189,6 @@
         return this;
     }
 
-    public PackageStateUnserialized setApkInApex(boolean value) {
-        apkInApex = value;
-        mPackageSetting.onChanged();
-        return this;
-    }
-
     public PackageStateUnserialized setApkInUpdatedApex(boolean value) {
         apkInUpdatedApex = value;
         mPackageSetting.onChanged();
@@ -218,6 +214,13 @@
         return this;
     }
 
+    @NonNull
+    public PackageStateUnserialized setApexModuleName(@NonNull String value) {
+        mApexModuleName = value;
+        mPackageSetting.onChanged();
+        return this;
+    }
+
 
 
     // Code below generated by codegen v1.0.23.
@@ -254,11 +257,6 @@
     }
 
     @DataClass.Generated.Member
-    public boolean isApkInApex() {
-        return apkInApex;
-    }
-
-    @DataClass.Generated.Member
     public boolean isApkInUpdatedApex() {
         return apkInUpdatedApex;
     }
@@ -292,11 +290,16 @@
         return mPackageSetting;
     }
 
+    @DataClass.Generated.Member
+    public @Nullable String getApexModuleName() {
+        return mApexModuleName;
+    }
+
     @DataClass.Generated(
-            time = 1666291743725L,
+            time = 1671483772254L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java",
-            inputSignatures = "private  boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibraryWrapper> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate  boolean updatedSystemApp\nprivate  boolean apkInApex\nprivate  boolean apkInUpdatedApex\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\nprivate @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate @android.annotation.NonNull java.lang.String seInfo\nprivate final @android.annotation.NonNull com.android.server.pm.PackageSetting mPackageSetting\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryInfo(com.android.server.pm.pkg.SharedLibraryWrapper)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryFile(java.lang.String)\nprivate  long[] lazyInitLastPackageUsageTimeInMills()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic  long getLatestPackageUseTimeInMills()\npublic  long getLatestForegroundPackageUseTimeInMills()\npublic  void updateFrom(com.android.server.pm.pkg.PackageStateUnserialized)\npublic @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> getNonNativeUsesLibraryInfos()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setHiddenUntilInstalled(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryInfos(java.util.List<android.content.pm.SharedLibraryInfo>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryFiles(java.util.List<java.lang.String>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUpdatedSystemApp(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setApkInApex(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setApkInUpdatedApex(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(long)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setOverrideSeInfo(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized setSeInfo(java.lang.String)\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)")
+            inputSignatures = "private  boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibraryWrapper> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate  boolean updatedSystemApp\nprivate  boolean apkInUpdatedApex\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\nprivate @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate @android.annotation.NonNull java.lang.String seInfo\nprivate final @android.annotation.NonNull com.android.server.pm.PackageSetting mPackageSetting\nprivate @android.annotation.Nullable java.lang.String mApexModuleName\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryInfo(com.android.server.pm.pkg.SharedLibraryWrapper)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryFile(java.lang.String)\nprivate  long[] lazyInitLastPackageUsageTimeInMills()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic  long getLatestPackageUseTimeInMills()\npublic  long getLatestForegroundPackageUseTimeInMills()\npublic  void updateFrom(com.android.server.pm.pkg.PackageStateUnserialized)\npublic @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> getNonNativeUsesLibraryInfos()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setHiddenUntilInstalled(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryInfos(java.util.List<android.content.pm.SharedLibraryInfo>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryFiles(java.util.List<java.lang.String>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUpdatedSystemApp(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setApkInUpdatedApex(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(long)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setOverrideSeInfo(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized setSeInfo(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized setApexModuleName(java.lang.String)\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index 60dbbdd..3fcb08a 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -710,6 +710,11 @@
                 if (gnssChargeUC != EnergyConsumerSnapshot.UNAVAILABLE) {
                     mStats.updateGnssEnergyConsumerStatsLocked(gnssChargeUC, elapsedRealtime);
                 }
+
+                final long cameraChargeUC = energyConsumerDeltas.cameraChargeUC;
+                if (cameraChargeUC != EnergyConsumerSnapshot.UNAVAILABLE) {
+                    mStats.updateCameraEnergyConsumerStatsLocked(cameraChargeUC, elapsedRealtime);
+                }
             }
             // Inform mStats about each applicable custom energy bucket.
             if (energyConsumerDeltas != null
@@ -904,6 +909,9 @@
                 case EnergyConsumerType.WIFI:
                     buckets[EnergyConsumerStats.POWER_BUCKET_WIFI] = true;
                     break;
+                case EnergyConsumerType.CAMERA:
+                    buckets[EnergyConsumerStats.POWER_BUCKET_CAMERA] = true;
+                    break;
             }
         }
         return buckets;
@@ -955,6 +963,9 @@
         if ((flags & UPDATE_WIFI) != 0) {
             addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.WIFI);
         }
+        if ((flags & UPDATE_CAMERA) != 0) {
+            addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.CAMERA);
+        }
 
         if (energyConsumerIds.size() == 0) {
             return null;
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index c559436..d622fd7 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -178,7 +178,7 @@
     // TODO: remove "tcp" from network methods, since we measure total stats.
 
     // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
-    public static final int VERSION = 210;
+    public static final int VERSION = 211;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -649,10 +649,12 @@
         int UPDATE_BT = 0x08;
         int UPDATE_RPM = 0x10;
         int UPDATE_DISPLAY = 0x20;
-        int RESET = 0x40;
+        int UPDATE_CAMERA = 0x40;
+        int RESET = 0x80;
 
         int UPDATE_ALL =
-                UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM | UPDATE_DISPLAY;
+                UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM | UPDATE_DISPLAY
+                        | UPDATE_CAMERA;
 
         int UPDATE_ON_PROC_STATE_CHANGE = UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT;
 
@@ -665,6 +667,7 @@
                 UPDATE_BT,
                 UPDATE_RPM,
                 UPDATE_DISPLAY,
+                UPDATE_CAMERA,
                 UPDATE_ALL,
         })
         @Retention(RetentionPolicy.SOURCE)
@@ -6244,6 +6247,8 @@
         }
         getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
                 .noteCameraTurnedOnLocked(elapsedRealtimeMs);
+
+        scheduleSyncExternalStatsLocked("camera-on", ExternalStatsSync.UPDATE_CAMERA);
     }
 
     @GuardedBy("this")
@@ -6259,6 +6264,8 @@
         }
         getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
                 .noteCameraTurnedOffLocked(elapsedRealtimeMs);
+
+        scheduleSyncExternalStatsLocked("camera-off", ExternalStatsSync.UPDATE_CAMERA);
     }
 
     @GuardedBy("this")
@@ -6273,6 +6280,8 @@
                 uid.noteResetCameraLocked(elapsedRealtimeMs);
             }
         }
+
+        scheduleSyncExternalStatsLocked("camera-reset", ExternalStatsSync.UPDATE_CAMERA);
     }
 
     @GuardedBy("this")
@@ -7414,6 +7423,12 @@
         return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_WIFI);
     }
 
+    @GuardedBy("this")
+    @Override
+    public long getCameraEnergyConsumptionUC() {
+        return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_CAMERA);
+    }
+
     /**
      * Returns the consumption (in microcoulombs) that the given standard power bucket consumed.
      * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable
@@ -8427,6 +8442,12 @@
                     processState);
         }
 
+        @GuardedBy("mBsi")
+        @Override
+        public long getCameraEnergyConsumptionUC() {
+            return getEnergyConsumptionUC(EnergyConsumerStats.POWER_BUCKET_CAMERA);
+        }
+
         /**
          * Gets the minimum of the uid's foreground activity time and its PROCESS_STATE_TOP time
          * since last marked. Also sets the mark time for both these timers.
@@ -8477,6 +8498,20 @@
             return gnssTimeUs;
         }
 
+        /**
+         * Gets the uid's time spent using the camera since last marked. Also sets the mark time for
+         * the camera timer.
+         */
+        private long markCameraTimeUs(long elapsedRealtimeMs) {
+            final StopwatchTimer timer = mCameraTurnedOnTimer;
+            if (timer == null) {
+                return 0;
+            }
+            final long cameraTimeUs = timer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000);
+            timer.setMark(elapsedRealtimeMs);
+            return cameraTimeUs;
+        }
+
         public StopwatchTimer createAudioTurnedOnTimerLocked() {
             if (mAudioTurnedOnTimer == null) {
                 mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, AUDIO_TURNED_ON,
@@ -12902,6 +12937,53 @@
     }
 
     /**
+     * Accumulate camera charge consumption and distribute it to the correct state and the apps.
+     *
+     * @param chargeUC amount of charge (microcoulombs) used by the camera since this was last
+     *         called.
+     */
+    @GuardedBy("this")
+    public void updateCameraEnergyConsumerStatsLocked(long chargeUC, long elapsedRealtimeMs) {
+        if (DEBUG_ENERGY) Slog.d(TAG, "Updating camera stats: " + chargeUC);
+        if (mGlobalEnergyConsumerStats == null) {
+            return;
+        }
+
+        if (!mOnBatteryInternal || chargeUC <= 0) {
+            // There's nothing further to update.
+            return;
+        }
+
+        if (mIgnoreNextExternalStats) {
+            // Although under ordinary resets we won't get here, and typically a new sync will
+            // happen right after the reset, strictly speaking we need to set all mark times to now.
+            final int uidStatsSize = mUidStats.size();
+            for (int i = 0; i < uidStatsSize; i++) {
+                final Uid uid = mUidStats.valueAt(i);
+                uid.markCameraTimeUs(elapsedRealtimeMs);
+            }
+            return;
+        }
+
+        mGlobalEnergyConsumerStats.updateStandardBucket(
+                EnergyConsumerStats.POWER_BUCKET_CAMERA, chargeUC);
+
+        // Collect the per uid time since mark so that we can normalize power.
+        final SparseDoubleArray cameraTimeUsArray = new SparseDoubleArray();
+
+        // Note: Iterating over all UIDs may be suboptimal.
+        final int uidStatsSize = mUidStats.size();
+        for (int i = 0; i < uidStatsSize; i++) {
+            final Uid uid = mUidStats.valueAt(i);
+            final long cameraTimeUs = uid.markCameraTimeUs(elapsedRealtimeMs);
+            if (cameraTimeUs == 0) continue;
+            cameraTimeUsArray.put(uid.getUid(), (double) cameraTimeUs);
+        }
+        distributeEnergyToUidsLocked(EnergyConsumerStats.POWER_BUCKET_CAMERA, chargeUC,
+                cameraTimeUsArray, 0, elapsedRealtimeMs);
+    }
+
+    /**
      * Accumulate Custom power bucket charge, globally and for each app.
      *
      * @param totalChargeUC charge (microcoulombs) used for this bucket since this was last called.
diff --git a/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java b/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java
index 16892034..89991bf 100644
--- a/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java
+++ b/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java
@@ -48,27 +48,44 @@
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
         super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query);
 
-        final long durationMs = batteryStats.getCameraOnTime(rawRealtimeUs,
-                BatteryStats.STATS_SINCE_CHARGED) / 1000;
-        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        long consumptionUc = batteryStats.getCameraEnergyConsumptionUC();
+        int powerModel = getPowerModel(consumptionUc, query);
+        long durationMs =
+                batteryStats.getCameraOnTime(
+                        rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000;
+        double powerMah;
+        if (powerModel == BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION) {
+            powerMah = uCtoMah(consumptionUc);
+        } else {
+            powerMah = mPowerEstimator.calculatePower(durationMs);
+        }
+
         builder.getAggregateBatteryConsumerBuilder(
-                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                 .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah);
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah, powerModel);
         builder.getAggregateBatteryConsumerBuilder(
-                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
                 .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah);
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah, powerModel);
     }
 
     @Override
     protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
-        final long durationMs =
+        long consumptionUc = app.getBatteryStatsUid().getCameraEnergyConsumptionUC();
+        int powerModel = getPowerModel(consumptionUc, query);
+        long durationMs =
                 mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(), rawRealtimeUs,
                         BatteryStats.STATS_SINCE_CHARGED);
-        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        double powerMah;
+        if (powerModel == BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION) {
+            powerMah = uCtoMah(consumptionUc);
+        } else {
+            powerMah = mPowerEstimator.calculatePower(durationMs);
+        }
+
         app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah);
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah, powerModel);
     }
 }
diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java b/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java
index 18595ca..939a08b 100644
--- a/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java
+++ b/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java
@@ -123,6 +123,9 @@
         /** The chargeUC for {@link EnergyConsumerType#WIFI}. */
         public long wifiChargeUC = UNAVAILABLE;
 
+        /** The chargeUC for {@link EnergyConsumerType#CAMERA}. */
+        public long cameraChargeUC = UNAVAILABLE;
+
         /** Map of {@link EnergyConsumerType#OTHER} ordinals to their total chargeUC. */
         public @Nullable long[] otherTotalChargeUC = null;
 
@@ -256,6 +259,10 @@
                     output.wifiChargeUC = deltaChargeUC;
                     break;
 
+                case EnergyConsumerType.CAMERA:
+                    output.cameraChargeUC = deltaChargeUC;
+                    break;
+
                 case EnergyConsumerType.OTHER:
                     if (output.otherTotalChargeUC == null) {
                         output.otherTotalChargeUC = new long[mNumOtherOrdinals];
@@ -458,6 +465,9 @@
                 case EnergyConsumerType.WIFI:
                     chargeUC[i] = delta.wifiChargeUC;
                     break;
+                case EnergyConsumerType.CAMERA:
+                    chargeUC[i] = delta.cameraChargeUC;
+                    break;
                 case EnergyConsumerType.OTHER:
                     if (delta.otherTotalChargeUC != null) {
                         chargeUC[i] = delta.otherTotalChargeUC[energyConsumer.ordinal];
diff --git a/services/core/java/com/android/server/resources/ResourcesManagerService.java b/services/core/java/com/android/server/resources/ResourcesManagerService.java
index eec3a02..94aa518 100644
--- a/services/core/java/com/android/server/resources/ResourcesManagerService.java
+++ b/services/core/java/com/android/server/resources/ResourcesManagerService.java
@@ -74,8 +74,8 @@
         @Override
         protected void dump(@NonNull FileDescriptor fd,
                 @NonNull PrintWriter pw, @Nullable String[] args) {
-            try {
-                mActivityManagerService.dumpAllResources(ParcelFileDescriptor.dup(fd), pw);
+            try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd)) {
+                mActivityManagerService.dumpAllResources(pfd, pw);
             } catch (Exception e) {
                 pw.println("Exception while trying to dump all resources: " + e.getMessage());
                 e.printStackTrace(pw);
diff --git a/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java b/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java
index 7d8336a..a75d110 100644
--- a/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java
+++ b/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java
@@ -62,13 +62,12 @@
 
     private int dumpResources() throws RemoteException {
         String processId = getNextArgRequired();
-        try {
+        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(getOutFileDescriptor())) {
             ConditionVariable lock = new ConditionVariable();
             RemoteCallback
                     finishCallback = new RemoteCallback(result -> lock.open(), null);
 
-            if (!mInterface.dumpResources(processId,
-                    ParcelFileDescriptor.dup(getOutFileDescriptor()), finishCallback)) {
+            if (!mInterface.dumpResources(processId, pfd, finishCallback)) {
                 getErrPrintWriter().println("RESOURCES DUMP FAILED on process " + processId);
                 return -1;
             }
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 6dc4b73..d4f2f2d 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -86,6 +87,11 @@
 public class TvInteractiveAppManagerService extends SystemService {
     private static final boolean DEBUG = false;
     private static final String TAG = "TvInteractiveAppManagerService";
+
+    private static final String METADATA_CLASS_NAME =
+            "android.media.tv.interactive.AppLinkInfo.ClassName";
+    private static final String METADATA_URI =
+            "android.media.tv.interactive.AppLinkInfo.Uri";
     // A global lock.
     private final Object mLock = new Object();
     private final Context mContext;
@@ -102,6 +108,8 @@
     // TODO: remove mGetServiceListCalled if onBootPhrase work correctly
     @GuardedBy("mLock")
     private boolean mGetServiceListCalled = false;
+    @GuardedBy("mLock")
+    private boolean mGetAppLinkInfoListCalled = false;
 
     private final UserManager mUserManager;
 
@@ -121,6 +129,41 @@
     }
 
     @GuardedBy("mLock")
+    private void buildAppLinkInfoLocked(int userId) {
+        UserState userState = getOrCreateUserStateLocked(userId);
+        if (DEBUG) {
+            Slogf.d(TAG, "buildAppLinkInfoLocked");
+        }
+        PackageManager pm = mContext.getPackageManager();
+        List<ApplicationInfo> appInfos = pm.getInstalledApplicationsAsUser(
+                PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA), userId);
+        List<AppLinkInfo> appLinkInfos = new ArrayList<>();
+        for (ApplicationInfo appInfo : appInfos) {
+            AppLinkInfo info = buildAppLinkInfoLocked(appInfo);
+            if (info != null) {
+                appLinkInfos.add(info);
+            }
+        }
+        // sort the list by package name
+        Collections.sort(appLinkInfos, Comparator.comparing(AppLinkInfo::getComponentName));
+        userState.mAppLinkInfoList.clear();
+        userState.mAppLinkInfoList.addAll(appLinkInfos);
+    }
+
+    @GuardedBy("mLock")
+    private AppLinkInfo buildAppLinkInfoLocked(ApplicationInfo appInfo) {
+        if (appInfo.metaData == null || appInfo.packageName == null) {
+            return null;
+        }
+        String className = appInfo.metaData.getString(METADATA_CLASS_NAME, null);
+        String uri = appInfo.metaData.getString(METADATA_URI, null);
+        if (className == null || uri == null) {
+            return null;
+        }
+        return new AppLinkInfo(appInfo.packageName, className, uri);
+    }
+
+    @GuardedBy("mLock")
     private void buildTvInteractiveAppServiceListLocked(int userId, String[] updatedPackages) {
         UserState userState = getOrCreateUserStateLocked(userId);
         userState.mPackageSet.clear();
@@ -311,6 +354,7 @@
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             synchronized (mLock) {
                 buildTvInteractiveAppServiceListLocked(mCurrentUserId, null);
+                buildAppLinkInfoLocked(mCurrentUserId);
             }
         }
     }
@@ -322,6 +366,7 @@
                 synchronized (mLock) {
                     if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
                         buildTvInteractiveAppServiceListLocked(userId, packages);
+                        buildAppLinkInfoLocked(userId);
                     }
                 }
             }
@@ -428,6 +473,7 @@
 
             mCurrentUserId = userId;
             buildTvInteractiveAppServiceListLocked(userId, null);
+            buildAppLinkInfoLocked(userId);
         }
     }
 
@@ -513,6 +559,7 @@
     private void startProfileLocked(int userId) {
         mRunningProfiles.add(userId);
         buildTvInteractiveAppServiceListLocked(userId, null);
+        buildAppLinkInfoLocked(userId);
     }
 
     @GuardedBy("mLock")
@@ -668,6 +715,26 @@
         }
 
         @Override
+        public List<AppLinkInfo> getAppLinkInfoList(int userId) {
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, "getAppLinkInfoList");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    if (!mGetAppLinkInfoListCalled) {
+                        buildAppLinkInfoLocked(userId);
+                        mGetAppLinkInfoListCalled = true;
+                    }
+                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    List<AppLinkInfo> appLinkInfos = new ArrayList<>(userState.mAppLinkInfoList);
+                    return appLinkInfos;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void registerAppLinkInfo(String tiasId, AppLinkInfo appLinkInfo, int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "registerAppLinkInfo: " + appLinkInfo);
@@ -1269,6 +1336,31 @@
         }
 
         @Override
+        public void sendCurrentVideoBounds(IBinder sessionToken, Rect bounds, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "sendCurrentVideoBounds(bounds=%s)", bounds.toString());
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "sendCurrentVideoBounds");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).sendCurrentVideoBounds(bounds);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in sendCurrentVideoBounds", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void sendCurrentChannelUri(IBinder sessionToken, Uri channelUri, int userId) {
             if (DEBUG) {
                 Slogf.d(TAG, "sendCurrentChannelUri(channelUri=%s)", channelUri.toString());
@@ -1996,6 +2088,8 @@
 
         // A set of all TV Interactive App service packages.
         private final Set<String> mPackageSet = new HashSet<>();
+        // A list of all app link infos.
+        private final List<AppLinkInfo> mAppLinkInfoList = new ArrayList<>();
 
         // A list of callbacks.
         private final RemoteCallbackList<ITvInteractiveAppManagerCallback> mCallbacks =
@@ -2406,6 +2500,23 @@
         }
 
         @Override
+        public void onRequestCurrentVideoBounds() {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestCurrentVideoBounds");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestCurrentVideoBounds(mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestCurrentVideoBounds", e);
+                }
+            }
+        }
+
+        @Override
         public void onRequestCurrentChannelUri() {
             synchronized (mLock) {
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index e2ab216..65127e4 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -891,8 +891,7 @@
                 // to show the border. We will do so when the pending message is handled.
                 if (!mHandler.hasMessages(
                         MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
-                    setMagnifiedRegionBorderShown(
-                            isMagnifying() || isForceShowingMagnifiableBounds(), true);
+                    setMagnifiedRegionBorderShown(isForceShowingMagnifiableBounds(), true);
                 }
             }
 
@@ -1057,7 +1056,7 @@
                 // rotation or folding/unfolding the device. In the rotation case, the screenshot
                 // used for rotation already has the border. After the rotation is complete
                 // we will show the border.
-                if (isMagnifying() || isForceShowingMagnifiableBounds()) {
+                if (isForceShowingMagnifiableBounds()) {
                     setMagnifiedRegionBorderShown(false, false);
                     final long delay = (long) (mLongAnimationDuration
                             * mService.getWindowAnimationScaleLocked());
@@ -1398,8 +1397,7 @@
 
                     case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
                         synchronized (mService.mGlobalLock) {
-                            if (mMagnifedViewport.isMagnifying()
-                                    || isForceShowingMagnifiableBounds()) {
+                            if (isForceShowingMagnifiableBounds()) {
                                 mMagnifedViewport.setMagnifiedRegionBorderShown(true, true);
                                 mService.scheduleAnimationLocked();
                             }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 4428be7..d4895ed 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -46,6 +46,7 @@
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -240,11 +241,21 @@
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityStopped");
             r = ActivityRecord.isInRootTaskLocked(token);
             if (r != null) {
+                if (!r.isState(STOPPING, RESTARTING_PROCESS)
+                        && mTaskSupervisor.hasScheduledRestartTimeouts(r)) {
+                    // Recover the restarting state which was replaced by other lifecycle changes.
+                    r.setState(RESTARTING_PROCESS, "continue-restart");
+                }
                 if (r.attachedToProcess() && r.isState(RESTARTING_PROCESS)) {
                     // The activity was requested to restart from
                     // {@link #restartActivityProcessIfVisible}.
                     restartingName = r.app.mName;
                     restartingUid = r.app.mUid;
+                    // Make EnsureActivitiesVisibleHelper#makeVisibleAndRestartIfNeeded not skip
+                    // restarting non-top activity.
+                    if (r != r.getTask().topRunningActivity()) {
+                        r.setVisibleRequested(false);
+                    }
                 }
                 r.activityStopped(icicle, persistentState, description);
             }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 45ae3d8..6abd3d7 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -9357,6 +9357,15 @@
             configChangeFlags = 0;
             return;
         }
+        if (!preserveWindow) {
+            // If the activity is the IME input target, ensure storing the last IME shown state
+            // before relaunching it for restoring the IME visibility once its new window focused.
+            final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget();
+            mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null
+                    && imeInputTarget.getWindowState().mActivityRecord == this
+                    && mDisplayContent.mInputMethodWindow != null
+                    && mDisplayContent.mInputMethodWindow.isVisible();
+        }
         // Do not waiting for translucent activity if it is going to relaunch.
         final Task rootTask = getRootTask();
         if (rootTask != null && rootTask.mTranslucentActivityWaiting == this) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 407ffd0..919bab8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2297,6 +2297,10 @@
         mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT);
     }
 
+    boolean hasScheduledRestartTimeouts(ActivityRecord r) {
+        return mHandler.hasMessages(RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG, r);
+    }
+
     void removeRestartTimeouts(ActivityRecord r) {
         mHandler.removeMessages(RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG, r);
     }
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index d395f12..db88f0f 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -36,7 +36,6 @@
 import android.animation.ArgbEvaluator;
 import android.content.Context;
 import android.graphics.Color;
-import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -251,9 +250,6 @@
                     screenshotBuffer.getColorSpace());
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
-            GraphicBuffer buffer = GraphicBuffer.createFromHardwareBuffer(
-                    screenshotBuffer.getHardwareBuffer());
-
             t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
             t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
             // If hdr layers are on-screen, e.g. picture-in-picture mode, the screenshot of
@@ -263,10 +259,11 @@
             t.setLayer(mBackColorSurface, -1);
             t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
             t.setAlpha(mBackColorSurface, 1);
-            t.setBuffer(mScreenshotLayer, buffer);
+            t.setBuffer(mScreenshotLayer, hardwareBuffer);
             t.setColorSpace(mScreenshotLayer, screenshotBuffer.getColorSpace());
             t.show(mScreenshotLayer);
             t.show(mBackColorSurface);
+            hardwareBuffer.close();
 
             if (mRoundedCornerOverlay != null) {
                 for (SurfaceControl sc : mRoundedCornerOverlay) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 5e081d5..e538584 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2406,7 +2406,7 @@
             if (isDisplayRotation) {
                 // This isn't cheap, so only do it for display rotations.
                 changeInfo.mSnapshotLuma = TransitionAnimation.getBorderLuma(
-                        screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
+                        buffer, screenshotBuffer.getColorSpace());
             }
             SurfaceControl.Transaction t = wc.mWmService.mTransactionFactory.get();
 
@@ -2418,6 +2418,7 @@
             t.setLayer(snapshotSurface, Integer.MAX_VALUE);
             t.apply();
             t.close();
+            buffer.close();
 
             // Detach the screenshot on the sync transaction (the screenshot is just meant to
             // freeze the window until the sync transaction is applied (with all its other
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4e7613b..0243a98 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -9177,6 +9177,7 @@
 
     boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
         final Task imeTargetWindowTask;
+        boolean hadRequestedShowIme = false;
         synchronized (mGlobalLock) {
             final WindowState imeTargetWindow = mWindowMap.get(imeTargetWindowToken);
             if (imeTargetWindow == null) {
@@ -9186,11 +9187,14 @@
             if (imeTargetWindowTask == null) {
                 return false;
             }
+            if (imeTargetWindow.mActivityRecord != null) {
+                hadRequestedShowIme = imeTargetWindow.mActivityRecord.mLastImeShown;
+            }
         }
         final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId,
                 imeTargetWindowTask.mUserId, false /* isLowResolution */,
                 false /* restoreFromDisk */);
-        return snapshot != null && snapshot.hasImeSurface();
+        return snapshot != null && snapshot.hasImeSurface() || hadRequestedShowIme;
     }
 
     @Override
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index 595d03d..be60946 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -39,15 +39,17 @@
         implements ProviderSession.ProviderInternalCallback<Void> {
     private static final String TAG = "GetRequestSession";
 
-    public ClearRequestSession(Context context, int userId,
+    public ClearRequestSession(Context context, int userId, int callingUid,
             IClearCredentialStateCallback callback, ClearCredentialStateRequest request,
             CallingAppInfo callingAppInfo) {
-        super(context, userId, request, callback, RequestInfo.TYPE_UNDEFINED, callingAppInfo);
+        super(context, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED,
+                callingAppInfo);
     }
 
     /**
      * Creates a new provider session, and adds it list of providers that are contributing to
      * this session.
+     *
      * @return the provider session created within this request session, for the given provider
      * info.
      */
@@ -111,8 +113,10 @@
         Log.i(TAG, "respondToClientWithResponseAndFinish");
         try {
             mClientCallback.onSuccess();
+            logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ true);
         } catch (RemoteException e) {
             Log.i(TAG, "Issue while propagating the response to the client");
+            logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ false);
         }
         finishSession();
     }
@@ -124,10 +128,12 @@
         } catch (RemoteException e) {
             e.printStackTrace();
         }
+        logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ false);
         finishSession();
     }
+
     private void processResponses() {
-        for (ProviderSession session: mProviders.values()) {
+        for (ProviderSession session : mProviders.values()) {
             if (session.isProviderResponseSet()) {
                 // If even one provider responded successfully, send back the response
                 // TODO: Aggregate other exceptions
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 4b26ccd..acfa491 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -44,11 +44,12 @@
         implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> {
     private static final String TAG = "CreateRequestSession";
 
-    CreateRequestSession(@NonNull Context context, int userId,
+    CreateRequestSession(@NonNull Context context, int userId, int callingUid,
             CreateCredentialRequest request,
             ICreateCredentialCallback callback,
             CallingAppInfo callingAppInfo) {
-        super(context, userId, request, callback, RequestInfo.TYPE_CREATE, callingAppInfo);
+        super(context, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE,
+                callingAppInfo);
     }
 
     /**
@@ -63,7 +64,7 @@
             RemoteCredentialService remoteCredentialService) {
         ProviderCreateSession providerCreateSession = ProviderCreateSession
                 .createNewSession(mContext, mUserId, providerInfo,
-                this, remoteCredentialService);
+                        this, remoteCredentialService);
         if (providerCreateSession != null) {
             Log.i(TAG, "In startProviderSession - provider session created and being added");
             mProviders.put(providerCreateSession.getComponentName().flattenToString(),
@@ -115,8 +116,10 @@
         Log.i(TAG, "respondToClientWithResponseAndFinish");
         try {
             mClientCallback.onResponse(response);
+            logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ true);
         } catch (RemoteException e) {
             Log.i(TAG, "Issue while responding to client: " + e.getMessage());
+            logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ false);
         }
         finishSession();
     }
@@ -128,6 +131,7 @@
         } catch (RemoteException e) {
             Log.i(TAG, "Issue while responding to client: " + e.getMessage());
         }
+        logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ false);
         finishSession();
     }
 
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index aefd300..f76cf49 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -269,11 +269,13 @@
             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
 
             int userId = UserHandle.getCallingUserId();
+            int callingUid = Binder.getCallingUid();
             // New request session, scoped for this request only.
             final GetRequestSession session =
                     new GetRequestSession(
                             getContext(),
                             userId,
+                            callingUid,
                             callback,
                             request,
                             constructCallingAppInfo(callingPackage, userId));
@@ -319,10 +321,12 @@
 
             // New request session, scoped for this request only.
             int userId = UserHandle.getCallingUserId();
+            int callingUid = Binder.getCallingUid();
             final CreateRequestSession session =
                     new CreateRequestSession(
                             getContext(),
                             userId,
+                            callingUid,
                             request,
                             callback,
                             constructCallingAppInfo(callingPackage, userId));
@@ -434,10 +438,12 @@
 
             // New request session, scoped for this request only.
             int userId = UserHandle.getCallingUserId();
+            int callingUid = Binder.getCallingUid();
             final ClearRequestSession session =
                     new ClearRequestSession(
                             getContext(),
                             userId,
+                            callingUid,
                             callback,
                             request,
                             constructCallingAppInfo(callingPackage, userId));
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index bbd0376..f7c5905 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -41,10 +41,10 @@
         implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
     private static final String TAG = "GetRequestSession";
 
-    public GetRequestSession(Context context, int userId,
+    public GetRequestSession(Context context, int userId, int callingUid,
             IGetCredentialCallback callback, GetCredentialRequest request,
             CallingAppInfo callingAppInfo) {
-        super(context, userId, request, callback, RequestInfo.TYPE_GET, callingAppInfo);
+        super(context, userId, callingUid, request, callback, RequestInfo.TYPE_GET, callingAppInfo);
     }
 
     /**
@@ -104,8 +104,10 @@
     private void respondToClientWithResponseAndFinish(GetCredentialResponse response) {
         try {
             mClientCallback.onResponse(response);
+            logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ true);
         } catch (RemoteException e) {
             Log.i(TAG, "Issue while responding to client with a response : " + e.getMessage());
+            logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ false);
         }
         finishSession();
     }
@@ -117,6 +119,7 @@
             Log.i(TAG, "Issue while responding to client with error : " + e.getMessage());
 
         }
+        logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ false);
         finishSession();
     }
 
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 9a99e34..95f2313 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -375,6 +375,11 @@
     private void onAuthenticationEntrySelected(
             @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
         //TODO: Other provider intent statuses
+        if (providerPendingIntentResponse == null) {
+            Log.i(TAG, "providerPendingIntentResponse is null");
+            onUpdateEmptyResponse();
+        }
+
         GetCredentialException exception = maybeGetPendingIntentException(
                 providerPendingIntentResponse);
         if (exception != null) {
@@ -393,7 +398,7 @@
         }
 
         Log.i(TAG, "No error or respond found in pending intent response");
-        invokeCallbackOnInternalInvalidState();
+        onUpdateEmptyResponse();
     }
 
     private void onActionEntrySelected(ProviderPendingIntentResponse
@@ -415,12 +420,16 @@
         }
     }
 
+    private void onUpdateEmptyResponse() {
+        updateStatusAndInvokeCallback(Status.NO_CREDENTIALS);
+    }
+
     @Nullable
     private GetCredentialException maybeGetPendingIntentException(
             ProviderPendingIntentResponse pendingIntentResponse) {
         if (pendingIntentResponse == null) {
             Log.i(TAG, "pendingIntentResponse is null");
-            return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
+            return null;
         }
         if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
             GetCredentialException exception = PendingIntentResultHandler
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 7036dfb..678c752 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -133,7 +133,7 @@
         PENDING_INTENT_INVOKED,
         CREDENTIAL_RECEIVED_FROM_SELECTION,
         SAVE_ENTRIES_RECEIVED, CANCELED,
-        COMPLETE
+        NO_CREDENTIALS, COMPLETE
     }
 
     /** Converts exception to a provider session status. */
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 0c3c34e..8e44f0f 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -16,6 +16,13 @@
 
 package com.android.server.credentials;
 
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS;
+
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.content.Context;
@@ -29,6 +36,8 @@
 import android.service.credentials.CredentialProviderInfo;
 import android.util.Log;
 
+import com.android.internal.util.FrameworkStatsLog;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
@@ -37,28 +46,53 @@
  * Base class of a request session, that listens to UI events. This class must be extended
  * every time a new response type is expected from the providers.
  */
-abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialManagerUiCallback{
+abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialManagerUiCallback {
     private static final String TAG = "RequestSession";
 
+    // Metrics constants
+    private static final int METRICS_API_NAME_UNKNOWN =
+            CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN;
+    private static final int METRICS_API_NAME_GET_CREDENTIAL =
+            CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL;
+    private static final int METRICS_API_NAME_CREATE_CREDENTIAL =
+            CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL;
+    private static final int METRICS_API_NAME_CLEAR_CREDENTIAL =
+            CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
+    private static final int METRICS_API_STATUS_SUCCESS =
+            CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS;
+    private static final int METRICS_API_STATUS_FAILURE =
+            CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE;
+
     // TODO: Revise access levels of attributes
-    @NonNull protected final T mClientRequest;
-    @NonNull protected final U mClientCallback;
-    @NonNull protected final IBinder mRequestId;
-    @NonNull protected final Context mContext;
-    @NonNull protected final CredentialManagerUi mCredentialManagerUi;
-    @NonNull protected final String mRequestType;
-    @NonNull protected final Handler mHandler;
-    @UserIdInt protected final int mUserId;
-    @NonNull protected final CallingAppInfo mClientAppInfo;
+    @NonNull
+    protected final T mClientRequest;
+    @NonNull
+    protected final U mClientCallback;
+    @NonNull
+    protected final IBinder mRequestId;
+    @NonNull
+    protected final Context mContext;
+    @NonNull
+    protected final CredentialManagerUi mCredentialManagerUi;
+    @NonNull
+    protected final String mRequestType;
+    @NonNull
+    protected final Handler mHandler;
+    @UserIdInt
+    protected final int mUserId;
+    private final int mCallingUid;
+    @NonNull
+    protected final CallingAppInfo mClientAppInfo;
 
     protected final Map<String, ProviderSession> mProviders = new HashMap<>();
 
     protected RequestSession(@NonNull Context context,
-            @UserIdInt int userId, @NonNull T clientRequest, U clientCallback,
+            @UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback,
             @NonNull String requestType,
             CallingAppInfo callingAppInfo) {
         mContext = context;
         mUserId = userId;
+        mCallingUid = callingUid;
         mClientRequest = clientRequest;
         mClientCallback = clientCallback;
         mRequestType = requestType;
@@ -117,6 +151,33 @@
         return false;
     }
 
+    // TODO: move these definitions to a separate logging focused class.
+    enum RequestType {
+        GET_CREDENTIALS,
+        CREATE_CREDENTIALS,
+        CLEAR_CREDENTIALS,
+    }
+
+    private static int getApiNameFromRequestType(RequestType requestType) {
+        switch (requestType) {
+            case GET_CREDENTIALS:
+                return METRICS_API_NAME_GET_CREDENTIAL;
+            case CREATE_CREDENTIALS:
+                return METRICS_API_NAME_CREATE_CREDENTIAL;
+            case CLEAR_CREDENTIALS:
+                return METRICS_API_NAME_CLEAR_CREDENTIAL;
+            default:
+                return METRICS_API_NAME_UNKNOWN;
+        }
+    }
+
+    protected void logApiCalled(RequestType requestType, boolean isSuccessful) {
+        FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED,
+                /* api_name */getApiNameFromRequestType(requestType), /* caller_uid */
+                mCallingUid, /* api_status */
+                isSuccessful ? METRICS_API_STATUS_SUCCESS : METRICS_API_STATUS_FAILURE);
+    }
+
     /**
      * Returns true if at least one provider is ready for UI invocation, and no
      * provider is pending a response.
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
new file mode 100644
index 0000000..73d04c6
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import static android.inputmethodservice.InputMethodService.IME_ACTIVE;
+
+import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SOFT_INPUT;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_SOFT_INPUT;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_INVALID;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.os.RemoteException;
+import android.view.inputmethod.InputMethodManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test the behavior of {@link DefaultImeVisibilityApplier} when performing or applying the IME
+ * visibility state.
+ *
+ * Build/Install/Run:
+ * atest FrameworksInputMethodSystemServerTests:DefaultImeVisibilityApplierTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTestBase {
+    private DefaultImeVisibilityApplier mVisibilityApplier;
+
+    @Before
+    public void setUp() throws RemoteException {
+        super.setUp();
+        mVisibilityApplier =
+                (DefaultImeVisibilityApplier) mInputMethodManagerService.getVisibilityApplier();
+        mInputMethodManagerService.mCurFocusedWindowClient = mock(
+                InputMethodManagerService.ClientState.class);
+    }
+
+    @Test
+    public void testPerformShowIme() throws Exception {
+        mVisibilityApplier.performShowIme(mWindowToken, null, null, SHOW_SOFT_INPUT);
+        verifyShowSoftInput(false, true, InputMethodManager.SHOW_IMPLICIT);
+    }
+
+    @Test
+    public void testPerformHideIme() throws Exception {
+        mVisibilityApplier.performHideIme(mWindowToken, null, null, HIDE_SOFT_INPUT);
+        verifyHideSoftInput(false, true);
+    }
+
+    @Test
+    public void testApplyImeVisibility_throwForInvalidState() {
+        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_INVALID);
+        assertThrows(IllegalArgumentException.class,
+                () -> mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_INVALID));
+    }
+
+    @Test
+    public void testApplyImeVisibility_showIme() {
+        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME);
+        verify(mMockWindowManagerInternal).showImePostLayout(eq(mWindowToken), any());
+    }
+
+    @Test
+    public void testApplyImeVisibility_hideIme() {
+        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME);
+        verify(mMockWindowManagerInternal).hideIme(eq(mWindowToken), anyInt(), any());
+    }
+
+    @Test
+    public void testApplyImeVisibility_hideImeExplicit() throws Exception {
+        mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
+        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME_EXPLICIT);
+        verifyHideSoftInput(true, true);
+    }
+
+    @Test
+    public void testApplyImeVisibility_hideNotAlways() throws Exception {
+        mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
+        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME_NOT_ALWAYS);
+        verifyHideSoftInput(true, true);
+    }
+
+    @Test
+    public void testApplyImeVisibility_showImeImplicit() throws Exception {
+        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME_IMPLICIT);
+        verifyShowSoftInput(true, true, InputMethodManager.SHOW_IMPLICIT);
+    }
+}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
new file mode 100644
index 0000000..8415fe1
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
+
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
+import static com.android.server.inputmethod.InputMethodManagerService.FALLBACK_DISPLAY_ID;
+import static com.android.server.inputmethod.InputMethodManagerService.ImeDisplayValidator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.inputmethod.InputMethodManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test the behavior of {@link ImeVisibilityStateComputer} and {@link ImeVisibilityApplier} when
+ * requesting the IME visibility.
+ *
+ * Build/Install/Run:
+ * atest FrameworksInputMethodSystemServerTests:ImeVisibilityStateComputerTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTestBase {
+    private ImeVisibilityStateComputer mComputer;
+    private int mImeDisplayPolicy = DISPLAY_IME_POLICY_LOCAL;
+
+    @Before
+    public void setUp() throws RemoteException {
+        super.setUp();
+        ImeVisibilityStateComputer.Injector injector = new ImeVisibilityStateComputer.Injector() {
+            @Override
+            public WindowManagerInternal getWmService() {
+                return mMockWindowManagerInternal;
+            }
+
+            @Override
+            public ImeDisplayValidator getImeValidator() {
+                return displayId -> mImeDisplayPolicy;
+            }
+        };
+        mComputer = new ImeVisibilityStateComputer(mInputMethodManagerService, injector);
+    }
+
+    @Test
+    public void testRequestImeVisibility_showImplicit() {
+        initImeTargetWindowState(mWindowToken);
+        boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+        mComputer.requestImeVisibility(mWindowToken, res);
+
+        final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
+        assertThat(state).isNotNull();
+        assertThat(state.hasEdiorFocused()).isTrue();
+        assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED);
+        assertThat(state.isRequestedImeVisible()).isTrue();
+
+        assertThat(mComputer.mRequestedShowExplicitly).isFalse();
+    }
+
+    @Test
+    public void testRequestImeVisibility_showExplicit() {
+        initImeTargetWindowState(mWindowToken);
+        boolean res = mComputer.onImeShowFlags(null, 0 /* show explicit */);
+        mComputer.requestImeVisibility(mWindowToken, res);
+
+        final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
+        assertThat(state).isNotNull();
+        assertThat(state.hasEdiorFocused()).isTrue();
+        assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED);
+        assertThat(state.isRequestedImeVisible()).isTrue();
+
+        assertThat(mComputer.mRequestedShowExplicitly).isTrue();
+    }
+
+    @Test
+    public void testRequestImeVisibility_showImplicit_a11yNoImePolicy() {
+        // Precondition: set AccessibilityService#SHOW_MODE_HIDDEN policy
+        mComputer.getImePolicy().setA11yRequestNoSoftKeyboard(SHOW_MODE_HIDDEN);
+
+        initImeTargetWindowState(mWindowToken);
+        boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+        mComputer.requestImeVisibility(mWindowToken, res);
+
+        final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
+        assertThat(state).isNotNull();
+        assertThat(state.hasEdiorFocused()).isTrue();
+        assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED);
+        assertThat(state.isRequestedImeVisible()).isFalse();
+
+        assertThat(mComputer.mRequestedShowExplicitly).isFalse();
+    }
+
+    @Test
+    public void testRequestImeVisibility_showImplicit_imeHiddenPolicy() {
+        // Precondition: set IME hidden display policy before calling showSoftInput
+        mComputer.getImePolicy().setImeHiddenByDisplayPolicy(true);
+
+        initImeTargetWindowState(mWindowToken);
+        boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+        mComputer.requestImeVisibility(mWindowToken, res);
+
+        final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
+        assertThat(state).isNotNull();
+        assertThat(state.hasEdiorFocused()).isTrue();
+        assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED);
+        assertThat(state.isRequestedImeVisible()).isFalse();
+
+        assertThat(mComputer.mRequestedShowExplicitly).isFalse();
+    }
+
+    @Test
+    public void testRequestImeVisibility_hideNotAlways() {
+        // Precondition: ensure IME has shown before hiding request.
+        mComputer.setInputShown(true);
+
+        initImeTargetWindowState(mWindowToken);
+        assertThat(mComputer.canHideIme(null, InputMethodManager.HIDE_NOT_ALWAYS)).isTrue();
+        mComputer.requestImeVisibility(mWindowToken, false);
+
+        final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
+        assertThat(state).isNotNull();
+        assertThat(state.hasEdiorFocused()).isTrue();
+        assertThat(state.getSoftInputModeState()).isEqualTo(SOFT_INPUT_STATE_UNCHANGED);
+        assertThat(state.isRequestedImeVisible()).isFalse();
+    }
+
+    @Test
+    public void testComputeImeDisplayId() {
+        final ImeTargetWindowState state = mComputer.getOrCreateWindowState(mWindowToken);
+
+        mImeDisplayPolicy = DISPLAY_IME_POLICY_LOCAL;
+        mComputer.computeImeDisplayId(state, DEFAULT_DISPLAY);
+        assertThat(mComputer.getImePolicy().isImeHiddenByDisplayPolicy()).isFalse();
+        assertThat(state.getImeDisplayId()).isEqualTo(DEFAULT_DISPLAY);
+
+        mComputer.computeImeDisplayId(state, 10 /* displayId */);
+        assertThat(mComputer.getImePolicy().isImeHiddenByDisplayPolicy()).isFalse();
+        assertThat(state.getImeDisplayId()).isEqualTo(10);
+
+        mImeDisplayPolicy = DISPLAY_IME_POLICY_HIDE;
+        mComputer.computeImeDisplayId(state, 10 /* displayId */);
+        assertThat(mComputer.getImePolicy().isImeHiddenByDisplayPolicy()).isTrue();
+        assertThat(state.getImeDisplayId()).isEqualTo(INVALID_DISPLAY);
+
+        mImeDisplayPolicy = DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+        mComputer.computeImeDisplayId(state, 10 /* displayId */);
+        assertThat(mComputer.getImePolicy().isImeHiddenByDisplayPolicy()).isFalse();
+        assertThat(state.getImeDisplayId()).isEqualTo(FALLBACK_DISPLAY_ID);
+    }
+
+    private void initImeTargetWindowState(IBinder windowToken) {
+        final ImeTargetWindowState state = new ImeTargetWindowState(SOFT_INPUT_STATE_UNCHANGED,
+                0, true, true, true);
+        mComputer.setWindowState(windowToken, state);
+    }
+}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index 640bde3..804bb49 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -26,6 +26,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -200,9 +201,8 @@
                         "TestServiceThread",
                         Process.THREAD_PRIORITY_FOREGROUND, /* allowIo */
                         false);
-        mInputMethodManagerService =
-                new InputMethodManagerService(
-                        mContext, mServiceThread, mMockInputMethodBindingController);
+        mInputMethodManagerService = new InputMethodManagerService(mContext, mServiceThread,
+                mMockInputMethodBindingController);
 
         // Start a InputMethodManagerService.Lifecycle to publish and manage the lifecycle of
         // InputMethodManagerService, which is closer to the real situation.
@@ -239,12 +239,17 @@
 
     protected void verifyShowSoftInput(boolean setVisible, boolean showSoftInput)
             throws RemoteException {
+        verifyShowSoftInput(setVisible, showSoftInput, anyInt());
+    }
+
+    protected void verifyShowSoftInput(boolean setVisible, boolean showSoftInput, int showFlags)
+            throws RemoteException {
         synchronized (ImfLock.class) {
             verify(mMockInputMethodBindingController, times(setVisible ? 1 : 0))
                     .setCurrentMethodVisible();
         }
         verify(mMockInputMethod, times(showSoftInput ? 1 : 0))
-                .showSoftInput(any(), any(), anyInt(), any());
+                .showSoftInput(any(), any(), eq(showFlags), any());
     }
 
     protected void verifyHideSoftInput(boolean setNotVisible, boolean hideSoftInput)
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 83677c2..47e7a37 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -30,11 +30,16 @@
         "truth-prebuilt",
     ],
     static_libs: [
+        "ApexInstallHelper",
         "cts-host-utils",
         "frameworks-base-hostutils",
         "PackageManagerServiceHostTestsIntentVerifyUtils",
     ],
     test_suites: ["general-tests"],
+    data: [
+        ":PackageManagerTestApex",
+        ":PackageManagerTestApexApp",
+    ],
     java_resources: [
         ":PackageManagerTestOverlayActor",
         ":PackageManagerTestOverlay",
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/ApexUpdateTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/ApexUpdateTest.kt
new file mode 100644
index 0000000..44b4e30
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/ApexUpdateTest.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test
+
+import com.android.modules.testing.utils.ApexInstallHelper
+import com.android.tradefed.invoker.TestInformation
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.android.tradefed.testtype.junit4.BeforeClassWithInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class ApexUpdateTest : BaseHostJUnit4Test() {
+
+    companion object {
+        private const val APEX_NAME = "com.android.server.pm.test.apex"
+        private const val APK_IN_APEX_NAME = "$APEX_NAME.app"
+        private const val APK_FILE_NAME = "PackageManagerTestApexApp.apk"
+
+        private lateinit var apexInstallHelper: ApexInstallHelper
+
+        @JvmStatic
+        @BeforeClassWithInfo
+        fun initApexHelper(testInformation: TestInformation) {
+            apexInstallHelper = ApexInstallHelper(testInformation)
+        }
+
+        @JvmStatic
+        @AfterClass
+        fun revertChanges() {
+            apexInstallHelper.revertChanges()
+        }
+    }
+
+    @Before
+    @After
+    fun uninstallApp() {
+        device.uninstallPackage(APK_IN_APEX_NAME)
+    }
+
+    @Test
+    fun apexModuleName() {
+        // Install the test APEX and assert it's returned as the APEX module itself
+        // (null when not --include-apex)
+        apexInstallHelper.pushApexAndReboot("PackageManagerTestApex.apex")
+        assertModuleName(APEX_NAME).isNull()
+        assertModuleName(APEX_NAME, includeApex = true).isEqualTo(APEX_NAME)
+
+        // Check the APK-in-APEX, ensuring there is only 1 active package
+        assertModuleName(APK_IN_APEX_NAME).isEqualTo(APEX_NAME)
+        assertModuleName(APK_IN_APEX_NAME, hidden = true).isNull()
+
+        // Then install a /data update to the APK-in-APEX
+        device.installPackage(testInformation.getDependencyFile(APK_FILE_NAME, false), false)
+
+        // Verify same as above
+        assertModuleName(APEX_NAME, includeApex = true).isEqualTo(APEX_NAME)
+        assertModuleName(APK_IN_APEX_NAME).isEqualTo(APEX_NAME)
+
+        // But also check that the /data variant now has a hidden package
+        assertModuleName(APK_IN_APEX_NAME, hidden = true).isEqualTo(APEX_NAME)
+
+        // Reboot the device and check that values are preserved
+        device.reboot()
+        assertModuleName(APEX_NAME, includeApex = true).isEqualTo(APEX_NAME)
+        assertModuleName(APK_IN_APEX_NAME).isEqualTo(APEX_NAME)
+        assertModuleName(APK_IN_APEX_NAME, hidden = true).isEqualTo(APEX_NAME)
+
+        // Revert the install changes (delete system image APEX) and check that it's gone
+        apexInstallHelper.revertChanges()
+        assertModuleName(APEX_NAME, includeApex = true).isNull()
+
+        // Verify the module name is no longer associated with the APK-in-APEX,
+        // which is now just a regular /data APK with no hidden system variant.
+        // The assertion for the valid /data APK uses "null" because the value
+        // printed for normal packages is "apexModuleName=null". As opposed to
+        // a literal null indicating the package variant doesn't exist
+        assertModuleName(APK_IN_APEX_NAME).isEqualTo("null")
+        assertModuleName(APK_IN_APEX_NAME, hidden = true).isEqualTo(null)
+    }
+
+    private fun assertModuleName(
+        packageName: String,
+        hidden: Boolean = false,
+        includeApex: Boolean = false
+    ) = assertThat(
+        device.executeShellCommand(
+                "dumpsys package ${"--include-apex".takeIf { includeApex }} $packageName"
+        )
+            .lineSequence()
+            .map(String::trim)
+            .dropWhile { !it.startsWith(if (hidden) "Hidden system packages:" else "Packages:")}
+            .dropWhile { !it.startsWith("Package [$packageName]") }
+            .takeWhile { !it.startsWith("User 0:") }
+            .firstOrNull { it.startsWith("apexModuleName=") }
+            ?.removePrefix("apexModuleName=")
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Apex/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/Android.bp
new file mode 100644
index 0000000..aef365e
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2022 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: ["Android-Apache-2.0"],
+}
+
+apex {
+    name: "PackageManagerTestApex",
+    apps: ["PackageManagerTestApexApp"],
+    androidManifest: "AndroidManifestApex.xml",
+    file_contexts: ":apex.test-file_contexts",
+    key: "apex.test.key",
+    certificate: ":apex.test.certificate",
+    min_sdk_version: "33",
+    installable: true,
+    updatable: true,
+}
+
+android_test_helper_app {
+    name: "PackageManagerTestApexApp",
+    manifest: "AndroidManifestApp.xml",
+    sdk_version: "33",
+    min_sdk_version: "33",
+    apex_available: ["PackageManagerTestApex"],
+    certificate: ":apex.test.certificate",
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Apex/AndroidManifestApex.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/AndroidManifestApex.xml
new file mode 100644
index 0000000..575b2bc
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/AndroidManifestApex.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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 package="com.android.server.pm.test.apex">
+    <application/>
+</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Apex/AndroidManifestApp.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/AndroidManifestApp.xml
new file mode 100644
index 0000000..87fb5cc
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/AndroidManifestApp.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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 package="com.android.server.pm.test.apex.app">
+    <application/>
+</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Apex/apex_manifest.json b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/apex_manifest.json
new file mode 100644
index 0000000..b89581d
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.server.pm.test.apex",
+  "version": 1
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index 2f909aa..5b0e2f3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -518,6 +518,7 @@
         apexInfo.isActive = isActive;
         apexInfo.isFactory = isFactory;
         apexInfo.modulePath = apexFile.getPath();
+        apexInfo.preinstalledModulePath = apexFile.getPath();
         return apexInfo;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 8b36da5..d5aa7fe 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -413,8 +413,8 @@
         mDexOptThread.join(TEST_WAIT_TIMEOUT_MS);
         mCancelThread.join(TEST_WAIT_TIMEOUT_MS);
 
-        // Always reschedule for periodic job
-        verify(mJobServiceForIdle).jobFinished(mJobParametersForIdle, false);
+        // The job should be rescheduled.
+        verify(mJobServiceForIdle).jobFinished(mJobParametersForIdle, true /* wantsReschedule */);
         verifyLastControlDexOptBlockingCall(false);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 0780d21..d996e37 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -214,7 +214,8 @@
     }
 
     private void notRegistered_publicMethodsShouldBeBenign(int displayId) {
-        assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
+
         assertFalse(
                 mFullScreenMagnificationController.magnificationRegionContains(displayId, 100,
                         100));
@@ -646,9 +647,9 @@
                 .setScale(displayId, 1.5f, startCenter.x, startCenter.y, false,
                         SERVICE_ID_2);
         assertFalse(mFullScreenMagnificationController.resetIfNeeded(displayId, SERVICE_ID_1));
-        assertTrue(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */true, displayId);
         assertTrue(mFullScreenMagnificationController.resetIfNeeded(displayId, SERVICE_ID_2));
-        assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
     }
 
     @Test
@@ -667,7 +668,7 @@
         assertTrue(mFullScreenMagnificationController.resetIfNeeded(displayId, false));
         verify(mRequestObserver).onFullScreenMagnificationChanged(eq(displayId),
                 eq(INITIAL_MAGNIFICATION_REGION), any(MagnificationConfig.class));
-        assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
         assertFalse(mFullScreenMagnificationController.resetIfNeeded(displayId, false));
     }
 
@@ -731,7 +732,7 @@
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
         mStateListener.onAnimationEnd(mMockValueAnimator);
 
-        assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_0));
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
         verify(lastAnimationCallback).onResult(true);
     }
 
@@ -749,8 +750,8 @@
         mMessageCapturingHandler.sendAllMessages();
         br.onReceive(mMockContext, null);
         mMessageCapturingHandler.sendAllMessages();
-        assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_0));
-        assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_1));
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, DISPLAY_0);
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, DISPLAY_1);
     }
 
     @Test
@@ -768,7 +769,7 @@
         mMessageCapturingHandler.sendAllMessages();
         callbacks.onUserContextChanged();
         mMessageCapturingHandler.sendAllMessages();
-        assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
     }
 
     @Test
@@ -784,10 +785,10 @@
         MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        assertTrue(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */true, displayId);
         callbacks.onDisplaySizeChanged();
         mMessageCapturingHandler.sendAllMessages();
-        assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, DISPLAY_0);
     }
 
     @Test
@@ -1133,23 +1134,17 @@
     }
 
     @Test
-    public void testSetForceShowMagnifiableBounds() {
+    public void testZoomTo1x_shouldActivatedAndForceShowMagnifiableBounds() {
         register(DISPLAY_0);
+        final float scale = 1.0f;
+        mFullScreenMagnificationController.setScaleAndCenter(
+                DISPLAY_0, scale, Float.NaN, Float.NaN, true, SERVICE_ID_1);
 
-        mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
-
+        checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */false, DISPLAY_0);
         verify(mMockWindowManager).setForceShowMagnifiableBounds(DISPLAY_0, true);
     }
 
     @Test
-    public void testIsForceShowMagnifiableBounds() {
-        register(DISPLAY_0);
-        mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
-
-        assertTrue(mFullScreenMagnificationController.isForceShowMagnifiableBounds(DISPLAY_0));
-    }
-
-    @Test
     public void testSetScale_toMagnifying_shouldNotifyActivatedState() {
         setScaleToMagnifying();
 
@@ -1220,7 +1215,15 @@
         float scale = 2.0f;
         mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y,
                 false, SERVICE_ID_1);
-        assertTrue(mFullScreenMagnificationController.isMagnifying(displayId));
+        checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */true, displayId);
+    }
+
+    private void checkActivatedAndMagnifyingState(
+            boolean activated, boolean magnifying, int displayId) {
+        final boolean isActivated = mFullScreenMagnificationController.isActivated(displayId);
+        final boolean isMagnifying = mFullScreenMagnificationController.getScale(displayId) > 1.0f;
+        assertTrue(isActivated == activated);
+        assertTrue(isMagnifying == magnifying);
     }
 
     private MagnificationCallbacks getMagnificationCallbacks(int displayId) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 0fed89b..5334e4c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -19,6 +19,7 @@
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT;
 import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
 
@@ -78,24 +79,25 @@
  * {@code
  *      digraph {
  *          IDLE -> SHORTCUT_TRIGGERED [label="a11y\nbtn"]
- *          SHORTCUT_TRIGGERED -> IDLE [label="a11y\nbtn"]
  *          IDLE -> DOUBLE_TAP [label="2tap"]
  *          DOUBLE_TAP -> IDLE [label="timeout"]
- *          DOUBLE_TAP -> TRIPLE_TAP_AND_HOLD [label="down"]
- *          SHORTCUT_TRIGGERED -> TRIPLE_TAP_AND_HOLD [label="down"]
- *          TRIPLE_TAP_AND_HOLD -> ZOOMED [label="up"]
- *          TRIPLE_TAP_AND_HOLD -> DRAGGING_TMP [label="hold/\nswipe"]
- *          DRAGGING_TMP -> IDLE [label="release"]
+ *          DOUBLE_TAP -> ZOOMED [label="tap"]
+ *          DOUBLE_TAP -> NON_ACTIVATED_ZOOMED_TMP [label="hold"]
+ *          NON_ACTIVATED_ZOOMED_TMP -> IDLE [label="release"]
+ *          SHORTCUT_TRIGGERED -> IDLE [label="a11y\nbtn"]
+ *          SHORTCUT_TRIGGERED -> ZOOMED[label="tap"]
+ *          SHORTCUT_TRIGGERED -> ACTIVATED_ZOOMED_TMP [label="hold"]
+ *          SHORTCUT_TRIGGERED -> PANNING [label="2hold]
  *          ZOOMED -> ZOOMED_DOUBLE_TAP [label="2tap"]
- *          ZOOMED_DOUBLE_TAP -> ZOOMED [label="timeout"]
- *          ZOOMED_DOUBLE_TAP -> DRAGGING [label="hold"]
- *          ZOOMED_DOUBLE_TAP -> IDLE [label="tap"]
- *          DRAGGING -> ZOOMED [label="release"]
  *          ZOOMED -> IDLE [label="a11y\nbtn"]
  *          ZOOMED -> PANNING [label="2hold"]
+ *          ZOOMED_DOUBLE_TAP -> ZOOMED [label="timeout"]
+ *          ZOOMED_DOUBLE_TAP -> ACTIVATED_ZOOMED_TMP [label="hold"]
+ *          ZOOMED_DOUBLE_TAP -> IDLE [label="tap"]
+ *          ACTIVATED_ZOOMED_TMP -> ZOOMED [label="release"]
+ *          PANNING -> ZOOMED [label="release"]
  *          PANNING -> PANNING_SCALING [label="pinch"]
  *          PANNING_SCALING -> ZOOMED [label="release"]
- *          PANNING -> ZOOMED [label="release"]
  *      }
  * }
  */
@@ -107,12 +109,11 @@
     public static final int STATE_2TAPS = 3;
     public static final int STATE_ZOOMED_2TAPS = 4;
     public static final int STATE_SHORTCUT_TRIGGERED = 5;
-    public static final int STATE_DRAGGING_TMP = 6;
-    public static final int STATE_DRAGGING = 7;
+    public static final int STATE_NON_ACTIVATED_ZOOMED_TMP = 6;
+    public static final int STATE_ACTIVATED_ZOOMED_TMP = 7;
     public static final int STATE_PANNING = 8;
     public static final int STATE_SCALING_AND_PANNING = 9;
 
-
     public static final int FIRST_STATE = STATE_IDLE;
     public static final int LAST_STATE = STATE_SCALING_AND_PANNING;
 
@@ -164,10 +165,6 @@
             public boolean magnificationRegionContains(int displayId, float x, float y) {
                 return true;
             }
-
-            @Override
-            void setForceShowMagnifiableBounds(int displayId, boolean show) {
-            }
         };
         mFullScreenMagnificationController.register(DISPLAY_0);
         mClock = new OffsettableClock.Stopped();
@@ -266,11 +263,11 @@
     @SuppressWarnings("Convert2MethodRef")
     @Test
     public void testAlternativeTransitions_areWorking() {
-        // A11y button followed by a tap&hold turns temporary "viewport dragging" zoom on
+        // A11y button followed by a tap&hold turns temporary "viewport dragging" zoom in
         assertTransition(STATE_SHORTCUT_TRIGGERED, () -> {
             send(downEvent());
             fastForward1sec();
-        }, STATE_DRAGGING_TMP);
+        }, STATE_ACTIVATED_ZOOMED_TMP);
 
         // A11y button followed by a tap turns zoom on
         assertTransition(STATE_SHORTCUT_TRIGGERED, () -> tap(), STATE_ZOOMED);
@@ -281,7 +278,6 @@
         // A11y button turns zoom off
         assertTransition(STATE_ZOOMED, () -> triggerShortcut(), STATE_IDLE);
 
-
         // Double tap times out while zoomed
         assertTransition(STATE_ZOOMED_2TAPS, () -> {
             allowEventDelegation();
@@ -291,8 +287,11 @@
         // tap+tap+swipe doesn't get delegated
         assertTransition(STATE_2TAPS, () -> swipe(), STATE_IDLE);
 
-        // tap+tap+swipe initiates viewport dragging immediately
-        assertTransition(STATE_2TAPS, () -> swipeAndHold(), STATE_DRAGGING_TMP);
+        // tap+tap+swipe&hold initiates temporary viewport dragging zoom in immediately
+        assertTransition(STATE_2TAPS, () -> swipeAndHold(), STATE_NON_ACTIVATED_ZOOMED_TMP);
+
+        // release when activated temporary zoom in back to zoomed
+        assertTransition(STATE_ACTIVATED_ZOOMED_TMP, () -> upEvent(), STATE_ZOOMED);
     }
 
     @Test
@@ -337,8 +336,10 @@
 
     @Test
     public void testTripleTapAndHold_zoomsImmediately() {
-        assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS);
-        assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED);
+        assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS, STATE_NON_ACTIVATED_ZOOMED_TMP);
+        assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED, STATE_ACTIVATED_ZOOMED_TMP);
+        assertZoomsImmediatelyOnSwipeFrom(STATE_ZOOMED_2TAPS, STATE_ACTIVATED_ZOOMED_TMP);
+
     }
 
     @Test
@@ -391,10 +392,10 @@
         PointF pointer3 = new PointF(DEFAULT_X * 2, DEFAULT_Y);
 
         send(downEvent());
-        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
-        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2, pointer3}));
-        send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}));
-        send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}));
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2, pointer3}, 2));
+        send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}, 2));
+        send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}, 2));
         send(upEvent());
 
         assertIn(STATE_ZOOMED);
@@ -411,38 +412,53 @@
     }
 
     @Test
-    public void testFirstFingerSwipe_TwoPinterDownAndZoomedState_panningState() {
+    public void testFirstFingerSwipe_twoPointerDownAndZoomedState_panningState() {
         goFromStateIdleTo(STATE_ZOOMED);
         PointF pointer1 = DEFAULT_POINT;
         PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
 
         send(downEvent());
-        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
         //The minimum movement to transit to panningState.
         final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
         pointer1.offset(sWipeMinDistance + 1, 0);
-        send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}));
+        send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
         assertIn(STATE_PANNING);
 
-        assertIn(STATE_PANNING);
         returnToNormalFrom(STATE_PANNING);
     }
 
     @Test
-    public void testSecondFingerSwipe_TwoPinterDownAndZoomedState_panningState() {
+    public void testSecondFingerSwipe_twoPointerDownAndZoomedState_panningState() {
         goFromStateIdleTo(STATE_ZOOMED);
         PointF pointer1 = DEFAULT_POINT;
         PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
 
         send(downEvent());
-        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
         //The minimum movement to transit to panningState.
         final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
         pointer2.offset(sWipeMinDistance + 1, 0);
-        send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}));
+        send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
         assertIn(STATE_PANNING);
 
+        returnToNormalFrom(STATE_PANNING);
+    }
+
+    @Test
+    public void testSecondFingerSwipe_twoPointerDownAndShortcutTriggeredState_panningState() {
+        goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED);
+        PointF pointer1 = DEFAULT_POINT;
+        PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
+        //The minimum movement to transit to panningState.
+        final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        pointer2.offset(sWipeMinDistance + 1, 0);
+        send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
         assertIn(STATE_PANNING);
+
         returnToNormalFrom(STATE_PANNING);
     }
 
@@ -474,11 +490,11 @@
         }
     }
 
-    private void assertZoomsImmediatelyOnSwipeFrom(int state) {
-        goFromStateIdleTo(state);
+    private void assertZoomsImmediatelyOnSwipeFrom(int fromState, int toState) {
+        goFromStateIdleTo(fromState);
         swipeAndHold();
-        assertIn(STATE_DRAGGING_TMP);
-        returnToNormalFrom(STATE_DRAGGING_TMP);
+        assertIn(toState);
+        returnToNormalFrom(toState);
     }
 
     private void assertTransition(int fromState, Runnable transitionAction, int toState) {
@@ -522,44 +538,51 @@
             case STATE_IDLE: {
                 check(tapCount() < 2, state);
                 check(!mMgh.mDetectingState.mShortcutTriggered, state);
+                check(!isActivated(), state);
                 check(!isZoomed(), state);
             } break;
             case STATE_ZOOMED: {
+                check(isActivated(), state);
                 check(isZoomed(), state);
                 check(tapCount() < 2, state);
             } break;
             case STATE_2TAPS: {
+                check(!isActivated(), state);
                 check(!isZoomed(), state);
                 check(tapCount() == 2, state);
             } break;
             case STATE_ZOOMED_2TAPS: {
+                check(isActivated(), state);
                 check(isZoomed(), state);
                 check(tapCount() == 2, state);
             } break;
-            case STATE_DRAGGING: {
+            case STATE_NON_ACTIVATED_ZOOMED_TMP: {
+                check(isActivated(), state);
                 check(isZoomed(), state);
                 check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
                         state);
-                check(mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
+                check(!mMgh.mViewportDraggingState.mActivatedBeforeDrag, state);
             } break;
-            case STATE_DRAGGING_TMP: {
+            case STATE_ACTIVATED_ZOOMED_TMP: {
+                check(isActivated(), state);
                 check(isZoomed(), state);
                 check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
                         state);
-                check(!mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
+                check(mMgh.mViewportDraggingState.mActivatedBeforeDrag, state);
             } break;
             case STATE_SHORTCUT_TRIGGERED: {
                 check(mMgh.mDetectingState.mShortcutTriggered, state);
+                check(isActivated(), state);
                 check(!isZoomed(), state);
             } break;
             case STATE_PANNING: {
-                check(isZoomed(), state);
+                check(isActivated(), state);
                 check(mMgh.mCurrentState == mMgh.mPanningScalingState,
                         state);
                 check(!mMgh.mPanningScalingState.mScaling, state);
             } break;
             case STATE_SCALING_AND_PANNING: {
-                check(isZoomed(), state);
+                check(isActivated(), state);
                 check(mMgh.mCurrentState == mMgh.mPanningScalingState,
                         state);
                 check(mMgh.mPanningScalingState.mScaling, state);
@@ -596,13 +619,13 @@
                     tap();
                     tap();
                 } break;
-                case STATE_DRAGGING: {
-                    goFromStateIdleTo(STATE_ZOOMED_2TAPS);
+                case STATE_NON_ACTIVATED_ZOOMED_TMP: {
+                    goFromStateIdleTo(STATE_2TAPS);
                     send(downEvent());
                     fastForward1sec();
                 } break;
-                case STATE_DRAGGING_TMP: {
-                    goFromStateIdleTo(STATE_2TAPS);
+                case STATE_ACTIVATED_ZOOMED_TMP: {
+                    goFromStateIdleTo(STATE_ZOOMED_2TAPS);
                     send(downEvent());
                     fastForward1sec();
                 } break;
@@ -654,13 +677,13 @@
             case STATE_ZOOMED_2TAPS: {
                 tap();
             } break;
-            case STATE_DRAGGING: {
+            case STATE_NON_ACTIVATED_ZOOMED_TMP: {
+                send(upEvent());
+            } break;
+            case STATE_ACTIVATED_ZOOMED_TMP: {
                 send(upEvent());
                 returnToNormalFrom(STATE_ZOOMED);
             } break;
-            case STATE_DRAGGING_TMP: {
-                send(upEvent());
-            } break;
             case STATE_SHORTCUT_TRIGGERED: {
                 triggerShortcut();
             } break;
@@ -682,8 +705,12 @@
         }
     }
 
+    private boolean isActivated() {
+        return mMgh.mFullScreenMagnificationController.isActivated(DISPLAY_0);
+    }
+
     private boolean isZoomed() {
-        return mMgh.mFullScreenMagnificationController.isMagnifying(DISPLAY_0);
+        return mMgh.mFullScreenMagnificationController.getScale(DISPLAY_0) > 1.0f;
     }
 
     private int tapCount() {
@@ -770,10 +797,10 @@
 
 
     private MotionEvent pointerEvent(int action, float x, float y) {
-        return pointerEvent(action, new PointF[] {DEFAULT_POINT, new PointF(x, y)});
+        return pointerEvent(action, new PointF[] {DEFAULT_POINT, new PointF(x, y)}, 1);
     }
 
-    private MotionEvent pointerEvent(int action, PointF[] pointersPosition) {
+    private MotionEvent pointerEvent(int action, PointF[] pointersPosition, int changedIndex) {
         final MotionEvent.PointerProperties[] PointerPropertiesArray =
                 new MotionEvent.PointerProperties[pointersPosition.length];
         for (int i = 0; i < pointersPosition.length; i++) {
@@ -792,6 +819,8 @@
             pointerCoordsArray[i] = pointerCoords;
         }
 
+        action += (changedIndex << ACTION_POINTER_INDEX_SHIFT);
+
         return MotionEvent.obtain(
                 /* downTime */ mClock.now(),
                 /* eventTime */ mClock.now(),
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 2a80ce0..231b2f32 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
@@ -495,16 +495,6 @@
     }
 
     @Test
-    public void setScaleOneThroughExternalRequest_fullScreenEnabled_removeMagnificationButton()
-            throws RemoteException {
-        setMagnificationEnabled(MODE_FULLSCREEN);
-        mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, 1.0f,
-                MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y, false, TEST_SERVICE_ID);
-
-        verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
-    }
-
-    @Test
     public void onPerformScaleAction_magnifierEnabled_handleScaleChange() throws RemoteException {
         final float newScale = 4.0f;
         setMagnificationEnabled(MODE_WINDOW);
@@ -756,7 +746,7 @@
 
         mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true);
 
-        assertFalse(mScreenMagnificationController.isMagnifying(TEST_DISPLAY));
+        verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY), eq(false));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index f5029ec..f2e03aa 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -165,6 +165,7 @@
                 awaitJobStart(DEFAULT_WAIT_TIMEOUT));
     }
 
+    @FlakyTest
     @Test
     public void testFeatureFlag() throws Exception {
         Settings.Global.putInt(mContext.getContentResolver(),
diff --git a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
index d80aa57..ccf530f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
@@ -539,7 +539,8 @@
             NoSuchFieldException, PackageManager.NameNotFoundException {
         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
-                /* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null,
+                /* initiatingPackageName = */ INSTALLER_NAME_1,
+                /* initiatingPackageSigningInfo = */ null,
                 /* originatingPackageName = */ null,
                 /* installingPackageName = */ INSTALLER_NAME_1);
         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
@@ -575,7 +576,8 @@
             NoSuchFieldException, PackageManager.NameNotFoundException {
         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
-                /* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null,
+                /* initiatingPackageName = */ INSTALLER_NAME_1,
+                /* initiatingPackageSigningInfo = */ null,
                 /* originatingPackageName = */ null,
                 /* installingPackageName = */ INSTALLER_NAME_1);
         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
@@ -619,7 +621,8 @@
             NoSuchFieldException, PackageManager.NameNotFoundException {
         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
-                /* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null,
+                /* initiatingPackageName = */ INSTALLER_NAME_1,
+                /* initiatingPackageSigningInfo = */ null,
                 /* originatingPackageName = */ null,
                 /* installingPackageName = */ INSTALLER_NAME_1);
         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
@@ -667,7 +670,8 @@
             NoSuchFieldException, PackageManager.NameNotFoundException {
         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
-                /* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null,
+                /* initiatingPackageName = */ INSTALLER_NAME_1,
+                /* initiatingPackageSigningInfo = */ null,
                 /* originatingPackageName = */ null,
                 /* installingPackageName = */ INSTALLER_NAME_1);
         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
@@ -711,7 +715,52 @@
         assertEquals(1, packages.size());
         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
     }
+    @Test
+    public void testHandleUsageEvent_packageAddedThroughAdb() throws
+            NoSuchFieldException, PackageManager.NameNotFoundException {
+        assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
+        InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+                /* initiatingPackageName = */ null, //currently ADB installer sets field to null
+                /* initiatingPackageSigningInfo = */ null,
+                /* originatingPackageName = */ null,
+                /* installingPackageName = */ INSTALLER_NAME_1);
+        // b/265203007
+        when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
+        ApplicationInfo appInfo = mock(ApplicationInfo.class);
 
+        when(mPackageManager.getApplicationInfoAsUser(
+                eq(PACKAGE_NAME_1),
+                any(),
+                anyInt())
+        ).thenReturn(appInfo);
+
+        long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
+                - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+        FieldSetter.setField(appInfo,
+                ApplicationInfo.class.getDeclaredField("createTimestamp"),
+                createTimestamp);
+
+        int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
+        assertEquals(USER_ID_1, UserHandle.getUserId(uid));
+
+        // The following  usage events generation is the same as
+        // testHandleUsageEvent_packageAddedOutsideTimeFrame2 test. The only difference is that
+        // for ADB installs the initiatingPackageName is null, despite being detected as a
+        // background install. Since we do not want to treat side-loaded apps as background install
+        // getBackgroundInstalledPackages() is expected to return null
+        doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+                anyString(), anyString(), anyInt());
+        generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+                USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+        generateUsageEvent(Event.ACTIVITY_STOPPED,
+                USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+
+        mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
+        mTestLooper.dispatchAll();
+
+        var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
+        assertNull(packages);
+    }
     @Test
     public void testPackageRemoved() {
         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
index 2ebe215..cff4cc7 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL;
 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_BT;
+import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_CAMERA;
 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU;
 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY;
 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO;
@@ -104,6 +105,11 @@
         tempAllIds.add(gnssId);
         mPowerStatsInternal.incrementEnergyConsumption(gnssId, 787878);
 
+        final int cameraId =
+                mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.CAMERA, 0, "camera");
+        tempAllIds.add(cameraId);
+        mPowerStatsInternal.incrementEnergyConsumption(cameraId, 901234);
+
         final int mobileRadioId = mPowerStatsInternal.addEnergyConsumer(
                 EnergyConsumerType.MOBILE_RADIO, 0, "mobile_radio");
         tempAllIds.add(mobileRadioId);
@@ -171,6 +177,12 @@
         Arrays.sort(receivedCpuIds);
         assertArrayEquals(cpuClusterIds, receivedCpuIds);
 
+        final EnergyConsumerResult[] cameraResults =
+                mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_CAMERA).getNow(null);
+        // Results should only have the camera energy consumer
+        assertEquals(1, cameraResults.length);
+        assertEquals(cameraId, cameraResults[0].id);
+
         final EnergyConsumerResult[] allResults =
                 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_ALL).getNow(null);
         // All energy consumer results should be available
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java b/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
index e4ab21b..5fce32f0 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
@@ -36,41 +36,113 @@
 public class CameraPowerCalculatorTest {
     private static final double PRECISION = 0.00001;
 
-    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+    private static final int APP1_UID = Process.FIRST_APPLICATION_UID + 42;
+    private static final int APP2_UID = Process.FIRST_APPLICATION_UID + 43;
 
     @Rule
     public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
-            .setAveragePower(PowerProfile.POWER_CAMERA, 360.0);
+            .setAveragePower(PowerProfile.POWER_CAMERA, 360.0)
+            .initMeasuredEnergyStatsLocked();
 
     @Test
     public void testTimerBasedModel() {
         BatteryStatsImpl stats = mStatsRule.getBatteryStats();
-        stats.noteCameraOnLocked(APP_UID, 1000, 1000);
-        stats.noteCameraOffLocked(APP_UID, 2000, 2000);
+        synchronized (stats) { // To keep the GuardedBy check happy
+            stats.noteCameraOnLocked(APP1_UID, 1000, 1000);
+            stats.noteCameraOffLocked(APP1_UID, 2000, 2000);
+            stats.noteCameraOnLocked(APP2_UID, 3000, 3000);
+            stats.noteCameraOffLocked(APP2_UID, 5000, 5000);
+        }
+
+        CameraPowerCalculator calculator =
+                new CameraPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
+
+        UidBatteryConsumer app1Consumer = mStatsRule.getUidBatteryConsumer(APP1_UID);
+        assertThat(app1Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(1000);
+        assertThat(app1Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isWithin(PRECISION).of(0.1);
+        assertThat(app1Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+
+        UidBatteryConsumer app2Consumer = mStatsRule.getUidBatteryConsumer(APP2_UID);
+        assertThat(app2Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(2000);
+        assertThat(app2Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isWithin(PRECISION).of(0.2);
+        assertThat(app2Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+
+        final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer();
+        assertThat(deviceBatteryConsumer
+                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(3000);
+        assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isWithin(PRECISION).of(0.3);
+        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+
+        final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer();
+        assertThat(appsBatteryConsumer
+                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(3000);
+        assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isWithin(PRECISION).of(0.3);
+        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+    }
+
+    @Test
+    public void testEnergyConsumptionBasedModel() {
+        BatteryStatsImpl stats = mStatsRule.getBatteryStats();
+        synchronized (stats) { // To keep the GuardedBy check happy
+            stats.noteCameraOnLocked(APP1_UID, 1000, 1000);
+            stats.noteCameraOffLocked(APP1_UID, 2000, 2000);
+            stats.updateCameraEnergyConsumerStatsLocked(720_000, 2100); // 0.72C == 0.2mAh
+            stats.noteCameraOnLocked(APP2_UID, 3000, 3000);
+            stats.noteCameraOffLocked(APP2_UID, 5000, 5000);
+            stats.updateCameraEnergyConsumerStatsLocked(1_080_000, 5100); // 0.3mAh
+        }
 
         CameraPowerCalculator calculator =
                 new CameraPowerCalculator(mStatsRule.getPowerProfile());
 
         mStatsRule.apply(calculator);
 
-        UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
-        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
+        UidBatteryConsumer app1Consumer = mStatsRule.getUidBatteryConsumer(APP1_UID);
+        assertThat(app1Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
                 .isEqualTo(1000);
-        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isWithin(PRECISION).of(0.1);
+        assertThat(app1Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isWithin(PRECISION).of(0.2);
+        assertThat(app1Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+
+        UidBatteryConsumer app2Consumer = mStatsRule.getUidBatteryConsumer(APP2_UID);
+        assertThat(app2Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(2000);
+        assertThat(app2Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isWithin(PRECISION).of(0.3);
+        assertThat(app2Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer();
         assertThat(deviceBatteryConsumer
                 .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(1000);
+                .isEqualTo(3000);
         assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isWithin(PRECISION).of(0.1);
+                .isWithin(PRECISION).of(0.5);
+        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsBatteryConsumer
                 .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isEqualTo(1000);
+                .isEqualTo(3000);
         assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
-                .isWithin(PRECISION).of(0.1);
+                .isWithin(PRECISION).of(0.5);
+        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java b/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
index 558f396..28f4799 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
@@ -248,6 +248,32 @@
         assertThat(details.toString()).isEqualTo("DISPLAY=2667 HPU=3200000 GPU=0 IPU &_=0");
     }
 
+    @Test
+    public void testUpdateAndGetDelta_updatesCameraCharge() {
+        EnergyConsumer cameraConsumer =
+                createEnergyConsumer(7, 0, EnergyConsumerType.CAMERA, "CAMERA");
+        final EnergyConsumerSnapshot snapshot =
+                new EnergyConsumerSnapshot(createIdToConsumerMap(cameraConsumer));
+
+        // An initial result with only one energy consumer
+        EnergyConsumerResult[] result0 = new EnergyConsumerResult[]{
+                createEnergyConsumerResult(cameraConsumer.id, 60_000, null, null),
+        };
+        snapshot.updateAndGetDelta(result0, VOLTAGE_1);
+
+        // A subsequent result
+        EnergyConsumerResult[] result1 = new EnergyConsumerResult[]{
+                createEnergyConsumerResult(cameraConsumer.id, 90_000, null, null),
+        };
+        EnergyConsumerDeltaData delta = snapshot.updateAndGetDelta(result1, VOLTAGE_1);
+
+        // Verify that the delta between the two results is reported.
+        BatteryStats.EnergyConsumerDetails details = snapshot.getEnergyConsumerDetails(delta);
+        assertThat(details.consumers).hasLength(1);
+        long expectedDeltaUC = calculateChargeConsumedUC(60_000, VOLTAGE_1, 90_000, VOLTAGE_1);
+        assertThat(details.chargeUC[0]).isEqualTo(expectedDeltaUC);
+    }
+
     private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) {
         final EnergyConsumer ec = new EnergyConsumer();
         ec.id = id;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 113f5ec..3eb7fe3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -295,6 +295,15 @@
 
         assertEquals(RESTARTING_PROCESS, mActivity.getState());
         assertNotEquals(originalOverrideBounds, mActivity.getBounds());
+
+        // Even if the state is changed (e.g. a floating activity on top is finished and make it
+        // resume), the restart procedure should recover the state and continue to kill the process.
+        mActivity.setState(RESUMED, "anyStateChange");
+        doReturn(true).when(mSupervisor).hasScheduledRestartTimeouts(mActivity);
+        mAtm.mActivityClientController.activityStopped(mActivity.token, null /* icicle */,
+                null /* persistentState */, null /* description */);
+        assertEquals(RESTARTING_PROCESS, mActivity.getState());
+        verify(mSupervisor).removeRestartTimeouts(mActivity);
     }
 
     @Test
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index a2a110d..26b4bbc 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -46,6 +46,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ISms;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.SmsRawData;
@@ -3508,4 +3509,41 @@
     private static String formatCrossStackMessageId(long id) {
         return "{x-message-id:" + id + "}";
     }
+
+    /**
+     * Fetches the EF_PSISMSC value from the UICC that contains the Public Service Identity of
+     * the SM-SC (either a SIP URI or tel URI). The EF_PSISMSC of ISIM and USIM can be found in
+     * DF_TELECOM.
+     * The EF_PSISMSC value is used by the ME to submit SMS over IP as defined in 24.341 [55].
+     *
+     * @return Uri : Public Service Identity of SM-SC from the ISIM or USIM if the ISIM is not
+     * available.
+     * @throws SecurityException if the caller does not have the required permission/privileges.
+     * @throws IllegalStateException in case of telephony service is not available.
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+    public Uri getSmscIdentity() {
+        Uri smscUri = Uri.EMPTY;
+        try {
+            IPhoneSubInfo info = TelephonyManager.getSubscriberInfoService();
+            if (info == null) {
+                Rlog.e(TAG, "getSmscIdentity(): IPhoneSubInfo instance is NULL");
+                throw new IllegalStateException("Telephony service is not available");
+            }
+            /** Fetches the SIM EF_PSISMSC value based on subId and appType */
+            smscUri = info.getSmscIdentity(getSubscriptionId(), TelephonyManager.APPTYPE_ISIM);
+            if (Uri.EMPTY.equals(smscUri)) {
+                /** Fallback in case where ISIM is not available */
+                smscUri = info.getSmscIdentity(getSubscriptionId(), TelephonyManager.APPTYPE_USIM);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getSmscIdentity(): Exception : " + ex);
+            ex.rethrowAsRuntimeException();
+        }
+        return smscUri;
+    }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0ad5ba0..4812806 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -17715,37 +17715,6 @@
     }
 
     /**
-     * Fetches the EFPSISMSC value from the SIM that contains the Public Service Identity
-     * of the SM-SC (either a SIP URI or tel URI), the value is common for both appType
-     * {@link #APPTYPE_ISIM} and {@link #APPTYPE_SIM}.
-     * The EFPSISMSC value is used by the ME to submit SMS over IP as defined in 24.341 [55].
-     *
-     * @param appType ICC Application type {@link #APPTYPE_ISIM} or {@link #APPTYPE_USIM}
-     * @return SIP URI or tel URI of the Public Service Identity of the SM-SC
-     * @throws SecurityException if the caller does not have the required permission/privileges
-     * @hide
-     */
-    @NonNull
-    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
-    public String getSmscIdentity(int appType) {
-        try {
-            IPhoneSubInfo info = getSubscriberInfoService();
-            if (info == null) {
-                Rlog.e(TAG, "getSmscIdentity(): IPhoneSubInfo instance is NULL");
-                return null;
-            }
-            /** Fetches the SIM PSISMSC params based on subId and appType */
-            return info.getSmscIdentity(getSubId(), appType);
-        } catch (RemoteException ex) {
-            Rlog.e(TAG, "getSmscIdentity(): RemoteException: " + ex.getMessage());
-        } catch (NullPointerException ex) {
-            Rlog.e(TAG, "getSmscIdentity(): NullPointerException: " + ex.getMessage());
-        }
-        return null;
-    }
-
-    /**
      * Returns a constant indicating the state of sim for the slot index.
      *
      * @param slotIndex Logical SIM slot index.
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 4fa7f43..3dfc81e 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.telephony.ImsiEncryptionInfo;
+import android.net.Uri;
 
 /**
  * Interface used to retrieve various phone-related subscriber information.
@@ -220,18 +221,17 @@
             String callingPackage, String callingFeatureId);
 
     /**
-     * Fetches the EFPSISMSC value from the SIM that contains the Public Service Identity
-     * of the SM-SC (either a SIP URI or tel URI), the value is common for both appType
-     * {@link #APPTYPE_ISIM} and {@link #APPTYPE_SIM}.
-     * The EFPSISMSC value is used by the ME to submit SMS over IP as defined in 24.341 [55].
+     * Fetches the EF_PSISMSC value from the UICC that contains the Public Service Identity of
+     * the SM-SC (either a SIP URI or tel URI). The EF_PSISMSC of ISIM and USIM can be found in
+     * DF_TELECOM.
+     * The EF_PSISMSC value is used by the ME to submit SMS over IP as defined in 24.341 [55].
      *
-     * @param appType ICC Application type {@link #APPTYPE_ISIM} or {@link #APPTYPE_USIM}
-     * @return SIP URI or tel URI of the Public Service Identity of the SM-SC
+     * @return Uri : Public Service Identity of SM-SC
      * @throws SecurityException if the caller does not have the required permission/privileges
      * @hide
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)")
-    String getSmscIdentity(int subId, int appType);
+    Uri getSmscIdentity(int subId, int appType);
 
     /**
      * Fetches the sim service table from the EFUST/EFIST based on the application type
@@ -249,9 +249,9 @@
      * @param appType of type int of either {@link #APPTYPE_USIM} or {@link #APPTYPE_ISIM}.
      * @return HexString represents sim service table else null.
      * @throws SecurityException if the caller does not have the required permission/privileges
+     * @throws IllegalStateException in case if phone or UiccApplication is not available.
      * @hide
      */
-
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)")
     String getSimServiceTable(int subId, int appType);
 }