Merge "Update how PeopleService is published"
diff --git a/Android.bp b/Android.bp
index 5af7756..4121b8a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -598,6 +598,12 @@
         "//frameworks/base/apex/jobscheduler/framework",
         "//frameworks/base/packages/Tethering/tests/unit",
     ],
+    errorprone: {
+        javacflags: [
+            "-Xep:AndroidFrameworkCompatChange:ERROR",
+            "-Xep:AndroidFrameworkUid:ERROR",
+        ],
+    },
 }
 
 // This "framework" module is NOT installed to the device. It's
diff --git a/StubLibraries.bp b/StubLibraries.bp
index a3a2094..0bcd76d 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -58,7 +58,24 @@
             "media/aidl",
         ],
     },
-    libs: ["framework-internal-utils"],
+    // These are libs from framework-internal-utils that are required (i.e. being referenced)
+    // from framework-non-updatable-sources. Add more here when there's a need.
+    // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular
+    // dependencies gets bigger.
+    libs: [
+        "android.hardware.cas-V1.2-java",
+        "android.hardware.health-V1.0-java-constants",
+        "android.hardware.radio-V1.5-java",
+        "android.hardware.thermal-V1.0-java-constants",
+        "android.hardware.thermal-V2.0-java",
+        "android.hardware.tv.input-V1.0-java-constants",
+        "android.hardware.tv.tuner-V1.0-java-constants",
+        "android.hardware.usb-V1.0-java-constants",
+        "android.hardware.usb-V1.1-java-constants",
+        "android.hardware.usb.gadget-V1.0-java",
+        "android.hardware.vibrator-V1.3-java",
+        "framework-protos",
+    ],
     installable: false,
     annotations_enabled: true,
     previous_api: ":android.api.public.latest",
diff --git a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
index bb6b691..66b2b0e 100644
--- a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
+++ b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
@@ -53,19 +53,19 @@
         final String text = mTextUtil.nextRandomParagraph(
                 WORD_LENGTH, 4 * 1024 * 1024 /* 4mb text */).toString();
         final RenderNode node = RenderNode.create("benchmark", null);
-        final RenderNode child = RenderNode.create("child", null);
-        child.setLeftTopRightBottom(50, 50, 100, 100);
-
-        RecordingCanvas canvas = node.start(100, 100);
-        node.end(canvas);
-        canvas = child.start(50, 50);
-        child.end(canvas);
 
         final Random r = new Random(0);
-
         while (state.keepRunning()) {
+            state.pauseTiming();
+            RecordingCanvas canvas = node.beginRecording();
             int start = r.nextInt(text.length() - 100);
+            state.resumeTiming();
+
             canvas.drawText(text, start, start + 100, 0, 0, PAINT);
+
+            state.pauseTiming();
+            node.endRecording();
+            state.resumeTiming();
         }
     }
 }
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index efcabd8..833cc0f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -226,7 +226,7 @@
             mMeasuredTimeNs = 0;
 
             final long startTime = SystemClock.elapsedRealtimeNanos();
-            atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
+            atm.startRecentsActivity(sRecentsIntent, 0 /* eventTime */, anim);
             final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime;
             mMeasuredTimeNs += elapsedTimeNsOfStart;
             state.addExtraResult("start", elapsedTimeNsOfStart);
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
index d2826d0..2b69863 100644
--- a/apex/media/framework/api/module-lib-current.txt
+++ b/apex/media/framework/api/module-lib-current.txt
@@ -1,14 +1,14 @@
 // Signature format: 2.0
 package android.media {
 
-  public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
-    ctor public MediaParceledListSlice(@NonNull java.util.List<T>);
-    method public int describeContents();
-    method @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
-    method public java.util.List<T> getList();
-    method public void setInlineCountLimit(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
+  @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
+    ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
+    method @Deprecated public java.util.List<T> getList();
+    method @Deprecated public void setInlineCountLimit(int);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
   }
 
 }
diff --git a/apex/media/framework/java/android/media/MediaParceledListSlice.java b/apex/media/framework/java/android/media/MediaParceledListSlice.java
index e1223f6..47ac193 100644
--- a/apex/media/framework/java/android/media/MediaParceledListSlice.java
+++ b/apex/media/framework/java/android/media/MediaParceledListSlice.java
@@ -17,7 +17,6 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,13 +31,16 @@
  * Transfer a large list of Parcelable objects across an IPC.  Splits into
  * multiple transactions if needed.
  *
- * @see BaseMediaParceledListSlice
- *
  * TODO: Remove this from @SystemApi once all the MediaSession related classes are moved
  *       to apex (or ParceledListSlice moved to apex). This class is temporaily added to system API
  *       for moving classes step by step.
+ *
+ * @param <T> The type of the elements in the list.
+ * @see BaseMediaParceledListSlice
+ * @deprecated This is temporary marked as @SystemApi. Should be removed from the API surface.
  * @hide
  */
+@Deprecated
 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class MediaParceledListSlice<T extends Parcelable>
         extends BaseMediaParceledListSlice<T> {
diff --git a/api/Android.bp b/api/Android.bp
index 490c980..e403082 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -64,6 +64,24 @@
 }
 
 genrule {
+    name: "frameworks-base-api-removed-merged.txt",
+    srcs: [
+        ":conscrypt.module.public.api{.public.removed-api.txt}",
+        ":framework-media{.public.removed-api.txt}",
+        ":framework-mediaprovider{.public.removed-api.txt}",
+        ":framework-permission{.public.removed-api.txt}",
+        ":framework-sdkextensions{.public.removed-api.txt}",
+        ":framework-statsd{.public.removed-api.txt}",
+        ":framework-tethering{.public.removed-api.txt}",
+        ":framework-wifi{.public.removed-api.txt}",
+        ":non-updatable-removed.txt",
+    ],
+    out: ["removed.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
     name: "frameworks-base-api-system-current-merged.txt",
     srcs: [
         ":framework-graphics{.system.api.txt}",
@@ -82,6 +100,23 @@
 }
 
 genrule {
+    name: "frameworks-base-api-system-removed-merged.txt",
+    srcs: [
+        ":framework-media{.system.removed-api.txt}",
+        ":framework-mediaprovider{.system.removed-api.txt}",
+        ":framework-permission{.system.removed-api.txt}",
+        ":framework-sdkextensions{.system.removed-api.txt}",
+        ":framework-statsd{.system.removed-api.txt}",
+        ":framework-tethering{.system.removed-api.txt}",
+        ":framework-wifi{.system.removed-api.txt}",
+        ":non-updatable-system-removed.txt",
+    ],
+    out: ["system-removed.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
     name: "frameworks-base-api-module-lib-current-merged.txt",
     srcs: [
         ":framework-graphics{.module-lib.api.txt}",
@@ -98,3 +133,20 @@
     tools: ["metalava"],
     cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
 }
+
+genrule {
+    name: "frameworks-base-api-module-lib-removed-merged.txt",
+    srcs: [
+        ":framework-media{.module-lib.removed-api.txt}",
+        ":framework-mediaprovider{.module-lib.removed-api.txt}",
+        ":framework-permission{.module-lib.removed-api.txt}",
+        ":framework-sdkextensions{.module-lib.removed-api.txt}",
+        ":framework-statsd{.module-lib.removed-api.txt}",
+        ":framework-tethering{.module-lib.removed-api.txt}",
+        ":framework-wifi{.module-lib.removed-api.txt}",
+        ":non-updatable-module-lib-removed.txt",
+    ],
+    out: ["module-lib-removed.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 3801e1d..19f348c 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -53,14 +53,14 @@
     field public static final int FLAG_FROM_KEY = 4096; // 0x1000
   }
 
-  public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
-    ctor public MediaParceledListSlice(@NonNull java.util.List<T>);
-    method public int describeContents();
-    method @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
-    method public java.util.List<T> getList();
-    method public void setInlineCountLimit(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
+  @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
+    ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
+    method @Deprecated public java.util.List<T> getList();
+    method @Deprecated public void setInlineCountLimit(int);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index e077ae4..21d3e84 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -95,6 +95,7 @@
     field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
     field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
     field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
+    field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
     field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
     field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
     field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
@@ -125,6 +126,7 @@
     field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
     field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
     field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+    field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION";
     field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
@@ -1389,6 +1391,57 @@
 
 }
 
+package android.app.time {
+
+  public final class TimeManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void addTimeZoneDetectorListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public android.app.time.TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void removeTimeZoneDetectorListener(@NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public boolean updateTimeZoneConfiguration(@NonNull android.app.time.TimeZoneConfiguration);
+  }
+
+  @java.lang.FunctionalInterface public static interface TimeManager.TimeZoneDetectorListener {
+    method public void onChange();
+  }
+
+  public final class TimeZoneCapabilities implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getConfigureAutoDetectionEnabledCapability();
+    method public int getConfigureGeoDetectionEnabledCapability();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_NOT_ALLOWED = 20; // 0x14
+    field public static final int CAPABILITY_NOT_APPLICABLE = 30; // 0x1e
+    field public static final int CAPABILITY_NOT_SUPPORTED = 10; // 0xa
+    field public static final int CAPABILITY_POSSESSED = 40; // 0x28
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilities> CREATOR;
+  }
+
+  public final class TimeZoneCapabilitiesAndConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.app.time.TimeZoneCapabilities getCapabilities();
+    method @NonNull public android.app.time.TimeZoneConfiguration getConfiguration();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilitiesAndConfig> CREATOR;
+  }
+
+  public final class TimeZoneConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isAutoDetectionEnabled();
+    method public boolean isGeoDetectionEnabled();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneConfiguration> CREATOR;
+  }
+
+  public static final class TimeZoneConfiguration.Builder {
+    ctor public TimeZoneConfiguration.Builder();
+    ctor public TimeZoneConfiguration.Builder(@NonNull android.app.time.TimeZoneConfiguration);
+    method @NonNull public android.app.time.TimeZoneConfiguration build();
+    method @NonNull public android.app.time.TimeZoneConfiguration.Builder setAutoDetectionEnabled(boolean);
+    method @NonNull public android.app.time.TimeZoneConfiguration.Builder setGeoDetectionEnabled(boolean);
+  }
+
+}
+
 package android.app.usage {
 
   public final class CacheQuotaHint implements android.os.Parcelable {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 42b560d..bda9e24 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3777,6 +3777,7 @@
         LAUNCHER = 1;
         NOTIFICATION = 2;
         LOCKSCREEN = 3;
+        RECENTS_ANIMATION = 4;
     }
     // The type of the startup source.
     optional SourceType source_type = 16;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a61159a..85cb120 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1910,6 +1910,8 @@
         public static final int TYPE_NOTIFICATION = 2;
         /** Launched from lockscreen, including notification while the device is locked. */
         public static final int TYPE_LOCKSCREEN = 3;
+        /** Launched from recents gesture handler. */
+        public static final int TYPE_RECENTS_ANIMATION = 4;
 
         @IntDef(flag = true, prefix = { "TYPE_" }, value = {
                 TYPE_LAUNCHER,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1a4db4e..1995128 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -25,7 +25,6 @@
 import android.app.IApplicationThread;
 import android.app.IActivityController;
 import android.app.IAppTask;
-import android.app.IAssistDataReceiver;
 import android.app.IInstrumentationWatcher;
 import android.app.IProcessObserver;
 import android.app.IServiceConnection;
@@ -70,7 +69,6 @@
 import android.os.StrictMode;
 import android.os.WorkSource;
 import android.service.voice.IVoiceInteractionSession;
-import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationAdapter;
 import com.android.internal.app.IVoiceInteractor;
@@ -470,11 +468,6 @@
     @UnsupportedAppUsage
     boolean isInLockTaskMode();
     @UnsupportedAppUsage
-    void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
-            in IRecentsAnimationRunner recentsAnimationRunner);
-    @UnsupportedAppUsage
-    void cancelRecentsAnimation(boolean restoreHomeStackPosition);
-    @UnsupportedAppUsage
     int startActivityFromRecents(int taskId, in Bundle options);
     @UnsupportedAppUsage
     void startSystemLockTaskMode(int taskId);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index e21ef8e..ddf2dc50 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -123,7 +123,7 @@
             in ProfilerInfo profilerInfo, in Bundle options, int userId);
     int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
             int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
-    void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
+    void startRecentsActivity(in Intent intent, in long eventTime,
             in IRecentsAnimationRunner recentsAnimationRunner);
     int startActivityFromRecents(int taskId, in Bundle options);
     int startActivityAsCaller(in IApplicationThread caller, in String callingPackage,
diff --git a/core/java/android/app/time/TimeManager.java b/core/java/android/app/time/TimeManager.java
index 9864afb..4796d8d 100644
--- a/core/java/android/app/time/TimeManager.java
+++ b/core/java/android/app/time/TimeManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.timezonedetector.ITimeZoneDetectorService;
 import android.content.Context;
@@ -36,7 +37,7 @@
  *
  * @hide
  */
-// @SystemApi
+@SystemApi
 @SystemService(Context.TIME_MANAGER)
 public final class TimeManager {
     private static final String TAG = "time.TimeManager";
diff --git a/core/java/android/app/time/TimeZoneCapabilities.java b/core/java/android/app/time/TimeZoneCapabilities.java
index c62c2b3..df89c28 100644
--- a/core/java/android/app/time/TimeZoneCapabilities.java
+++ b/core/java/android/app/time/TimeZoneCapabilities.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TimeZoneDetector;
 import android.os.Parcel;
@@ -50,7 +51,7 @@
  *
  * @hide
  */
-// @SystemApi
+@SystemApi
 public final class TimeZoneCapabilities implements Parcelable {
 
     /** @hide */
diff --git a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
index 6a04f3f..b339e53 100644
--- a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
+++ b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
@@ -17,6 +17,7 @@
 package android.app.time;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -27,7 +28,7 @@
  *
  * @hide
  */
-// @SystemApi
+@SystemApi
 public final class TimeZoneCapabilitiesAndConfig implements Parcelable {
 
     public static final @NonNull Creator<TimeZoneCapabilitiesAndConfig> CREATOR =
diff --git a/core/java/android/app/time/TimeZoneConfiguration.java b/core/java/android/app/time/TimeZoneConfiguration.java
index 488818a..c0a0c21 100644
--- a/core/java/android/app/time/TimeZoneConfiguration.java
+++ b/core/java/android/app/time/TimeZoneConfiguration.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.StringDef;
+import android.annotation.SystemApi;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -41,7 +42,7 @@
  *
  * @hide
  */
-// @SystemApi
+@SystemApi
 public final class TimeZoneConfiguration implements Parcelable {
 
     public static final @NonNull Creator<TimeZoneConfiguration> CREATOR =
@@ -188,7 +189,7 @@
      *
      * @hide
      */
-    // @SystemApi
+    @SystemApi
     public static final class Builder {
 
         private final Bundle mBundle = new Bundle();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 35c7b96..9a9f165 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2732,6 +2732,54 @@
     public static final String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
 
     /**
+     * Broadcast Action: Sent to indicate that the package becomes startable.
+     * The intent will have the following extra values:
+     * <ul>
+     * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. </li>
+     * <li> {@link #EXTRA_PACKAGE_NAME} containing the package name. </li>
+     * </li>
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
+
+    /**
+     * Broadcast Action: Sent to indicate that the package becomes unstartable.
+     * The intent will have the following extra values:
+     * <ul>
+     * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. </li>
+     * <li> {@link #EXTRA_PACKAGE_NAME} containing the package name. </li>
+     * <li> {@link #EXTRA_REASON} containing the integer indicating the reason for the state change,
+     * @see PackageManager.UnstartableReason
+     * </li>
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PACKAGE_UNSTARTABLE =
+            "android.intent.action.PACKAGE_UNSTARTABLE";
+
+    /**
+     * Broadcast Action: Sent to indicate that the package is fully loaded.
+     * <ul>
+     * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. </li>
+     * <li> {@link #EXTRA_PACKAGE_NAME} containing the package name. </li>
+     * </li>
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PACKAGE_FULLY_LOADED =
+            "android.intent.action.PACKAGE_FULLY_LOADED";
+
+    /**
      * Broadcast Action: A user ID has been removed from the system.  The user
      * ID number is stored in the extra data under {@link #EXTRA_UID}.
      *
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c2beab5..ea4b762 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1109,6 +1109,34 @@
     }
 
     /**
+     * Returns the reversed orientation.
+     * @hide
+     */
+    @ActivityInfo.ScreenOrientation
+    public static int reverseOrientation(@ActivityInfo.ScreenOrientation int orientation) {
+        switch (orientation) {
+            case SCREEN_ORIENTATION_LANDSCAPE:
+                return SCREEN_ORIENTATION_PORTRAIT;
+            case SCREEN_ORIENTATION_PORTRAIT:
+                return SCREEN_ORIENTATION_LANDSCAPE;
+            case SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+                return SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+            case SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+                return SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+            case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+                return SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+            case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+                return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+            case SCREEN_ORIENTATION_USER_LANDSCAPE:
+                return SCREEN_ORIENTATION_USER_PORTRAIT;
+            case SCREEN_ORIENTATION_USER_PORTRAIT:
+                return SCREEN_ORIENTATION_USER_LANDSCAPE;
+            default:
+                return orientation;
+        }
+    }
+
+    /**
      * Returns true if the activity supports picture-in-picture.
      * @hide
      */
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index efb00a0..745c39b 100644
--- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -50,7 +50,30 @@
     *            fail and all retry limits are exceeded. */
     const int DATA_LOADER_UNRECOVERABLE = 8;
 
+    /** There are no known issues with the data stream. */
+    const int STREAM_HEALTHY = 0;
+
+    /** There are issues with the current transport layer (network, adb connection, etc.) that may
+     * recover automatically or could eventually require user intervention. */
+    const int STREAM_TRANSPORT_ERROR = 1;
+
+    /** Integrity failures in the data stream, this could be due to file corruption, decompression
+     * issues or similar. This indicates a likely unrecoverable error. */
+    const int STREAM_INTEGRITY_ERROR = 2;
+
+    /** There are issues with the source of the data, e.g., backend availability issues, account
+     * issues. This indicates a potentially recoverable error, but one that may take a long time to
+     * resolve. */
+    const int STREAM_SOURCE_ERROR = 3;
+
+    /** The device or app is low on storage and cannot complete the stream as a result.
+      * A subsequent page miss resulting in app failure will transition app to unstartable state. */
+    const int STREAM_STORAGE_ERROR = 4;
+
     /** Data loader status callback */
     void onStatusChanged(in int dataLoaderId, in int status);
+
+    /** Callback to report streaming health status of a specific data loader */
+    void reportStreamHealth(in int dataLoaderId, in int streamStatus);
 }
 
diff --git a/core/java/android/content/pm/IncrementalStatesInfo.aidl b/core/java/android/content/pm/IncrementalStatesInfo.aidl
new file mode 100644
index 0000000..b5aad12
--- /dev/null
+++ b/core/java/android/content/pm/IncrementalStatesInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.server.pm;
+
+parcelable IncrementalStatesInfo;
\ No newline at end of file
diff --git a/core/java/android/content/pm/IncrementalStatesInfo.java b/core/java/android/content/pm/IncrementalStatesInfo.java
new file mode 100644
index 0000000..6e91c19
--- /dev/null
+++ b/core/java/android/content/pm/IncrementalStatesInfo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Info about a package's states in Parcelable format.
+ * @hide
+ */
+public class IncrementalStatesInfo implements Parcelable {
+    private boolean mIsStartable;
+    private boolean mIsLoading;
+    private float mProgress;
+
+    public IncrementalStatesInfo(boolean isStartable, boolean isLoading, float progress) {
+        mIsStartable = isStartable;
+        mIsLoading = isLoading;
+        mProgress = progress;
+    }
+
+    private IncrementalStatesInfo(Parcel source) {
+        mIsStartable = source.readBoolean();
+        mIsLoading = source.readBoolean();
+        mProgress = source.readFloat();
+    }
+
+    public boolean isStartable() {
+        return mIsStartable;
+    }
+
+    public boolean isLoading() {
+        return mIsLoading;
+    }
+
+    public float getProgress() {
+        return mProgress;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeBoolean(mIsStartable);
+        dest.writeBoolean(mIsLoading);
+        dest.writeFloat(mProgress);
+    }
+
+    public static final @android.annotation.NonNull Creator<IncrementalStatesInfo> CREATOR =
+            new Creator<IncrementalStatesInfo>() {
+                public IncrementalStatesInfo createFromParcel(Parcel source) {
+                    return new IncrementalStatesInfo(source);
+                }
+                public IncrementalStatesInfo[] newArray(int size) {
+                    return new IncrementalStatesInfo[size];
+                }
+            };
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a600d6c..c293e4ad 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3786,6 +3786,39 @@
      */
     public static final int SYSTEM_APP_STATE_UNINSTALLED = 3;
 
+    /**
+     * Reasons for why a package is unstartable.
+     * @hide
+     */
+    @IntDef({UNSTARTABLE_REASON_UNKNOWN,
+            UNSTARTABLE_REASON_DATALOADER_TRANSPORT,
+            UNSTARTABLE_REASON_DATALOADER_STORAGE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UnstartableReason {}
+
+    /**
+     * Unstartable state with no root cause specified. E.g., data loader seeing missing pages but
+     * unclear about the cause. This corresponds to a generic alert window shown to the user when
+     * the user attempts to launch the app.
+     * @hide
+     */
+    public static final int UNSTARTABLE_REASON_UNKNOWN = 0;
+
+    /**
+     * Unstartable state after hint from dataloader of issues with the transport layer.
+     * This corresponds to an alert window shown to the user indicating network errors.
+     * @hide
+     */
+    public static final int UNSTARTABLE_REASON_DATALOADER_TRANSPORT = 1;
+
+    /**
+     * Unstartable state after encountering storage limitations.
+     * This corresponds to an alert window indicating limited storage.
+     * @hide
+     */
+    public static final int UNSTARTABLE_REASON_DATALOADER_STORAGE = 2;
+
     /** {@hide} */
     public int getUserId() {
         return UserHandle.myUserId();
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 327d1b8..3ed21b0 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -44,7 +44,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index ca0981b..e62ad1f 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -852,12 +852,11 @@
 
     /**
      * Set the priority of a thread, based on Linux priorities.
-     *
-     * @param tid The identifier of the thread/process to change. It should be
-     * the native thread id but not the managed id of {@link java.lang.Thread}.
+     * 
+     * @param tid The identifier of the thread/process to change.
      * @param priority A Linux priority level, from -20 for highest scheduling
      * priority to 19 for lowest scheduling priority.
-     *
+     * 
      * @throws IllegalArgumentException Throws IllegalArgumentException if
      * <var>tid</var> does not exist.
      * @throws SecurityException Throws SecurityException if your process does
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 9e332e9..06203ff 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -657,16 +657,8 @@
         argsForZygote.add("--runtime-flags=" + runtimeFlags);
         if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
             argsForZygote.add("--mount-external-default");
-        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
-            argsForZygote.add("--mount-external-read");
-        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
-            argsForZygote.add("--mount-external-write");
-        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
-            argsForZygote.add("--mount-external-full");
         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
             argsForZygote.add("--mount-external-installer");
-        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
-            argsForZygote.add("--mount-external-legacy");
         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
             argsForZygote.add("--mount-external-pass-through");
         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1dbf95f..97acd2f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3567,6 +3567,9 @@
             if (outConfig.fontScale < 0) {
                 outConfig.fontScale = DEFAULT_FONT_SCALE;
             }
+            outConfig.forceBoldText = Settings.Secure.getIntForUser(
+                    cr, Settings.Secure.FORCE_BOLD_TEXT, Configuration.FORCE_BOLD_TEXT_NO,
+                    userHandle);
 
             final String localeValue =
                     Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle);
@@ -3597,6 +3600,7 @@
             if (!inoutConfig.userSetLocale && !inoutConfig.getLocales().isEmpty()) {
                 inoutConfig.clearLocales();
             }
+            inoutConfig.forceBoldText = Configuration.FORCE_BOLD_TEXT_UNDEFINED;
         }
 
         /**
@@ -3620,7 +3624,11 @@
                             DEFAULT_OVERRIDEABLE_BY_RESTORE);
         }
 
-        /** @hide */
+        /**
+         * Convenience function for checking if settings should be overwritten with config changes.
+         * @see #putConfigurationForUser(ContentResolver, Configuration, int)
+         * @hide
+         */
         public static boolean hasInterestingConfigurationChanges(int changes) {
             return (changes & ActivityInfo.CONFIG_FONT_SCALE) != 0 ||
                     (changes & ActivityInfo.CONFIG_LOCALE) != 0;
@@ -13407,15 +13415,6 @@
                 "power_button_very_long_press";
 
         /**
-         * Global settings that shouldn't be persisted.
-         *
-         * @hide
-         */
-        public static final String[] TRANSIENT_SETTINGS = {
-                LOCATION_GLOBAL_KILL_SWITCH,
-        };
-
-        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 44e603e..0c64eea 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -182,9 +182,6 @@
             IBinder displayToken, int mode);
     private static native void nativeDeferTransactionUntil(long transactionObj, long nativeObject,
             long barrierObject, long frame);
-    private static native void nativeDeferTransactionUntilSurface(long transactionObj,
-            long nativeObject,
-            long surfaceObject, long frame);
     private static native void nativeReparentChildren(long transactionObj, long nativeObject,
             long newParentObject);
     private static native void nativeReparent(long transactionObj, long nativeObject,
@@ -2947,22 +2944,6 @@
         /**
          * @hide
          */
-        @Deprecated
-        @UnsupportedAppUsage
-        public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
-                long frameNumber) {
-            if (frameNumber < 0) {
-                return this;
-            }
-            checkPreconditions(sc);
-            nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
-                    barrierSurface.mNativeObject, frameNumber);
-            return this;
-        }
-
-        /**
-         * @hide
-         */
         public Transaction reparentChildren(SurfaceControl sc, SurfaceControl newParent) {
             checkPreconditions(sc);
             nativeReparentChildren(mNativeObject, sc.mNativeObject, newParent.mNativeObject);
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index 5bcfa8b..2e5ee04 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -34,7 +34,7 @@
     private final UserInfo mUserInfo;
     private final PackageInfo mPackageInfo;
 
-    public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.S;
+    public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.R;
 
     public UserPackage(UserInfo user, PackageInfo packageInfo) {
         this.mUserInfo = user;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 5fc9344..8790bbd 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -47,7 +47,7 @@
     // visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
     /** @hide */
     private static final String CHROMIUM_WEBVIEW_FACTORY =
-            "com.android.webview.chromium.WebViewChromiumFactoryProviderForS";
+            "com.android.webview.chromium.WebViewChromiumFactoryProviderForR";
 
     private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
 
diff --git a/core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl b/core/java/com/android/ims/internal/uce/presence/PresCmdID.aidl
similarity index 100%
rename from core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresCmdID.aidl
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 900e18d..28a9601 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -166,7 +166,7 @@
 
         // Now fetch app icon and raster with no badging even in work profile
         Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info)
-                .getIconBitmap(UserHandle.getUserHandleForUid(UserHandle.myUserId()));
+                .getIconBitmap(android.os.Process.myUserHandle());
 
         // Raster target drawable with appIcon as a badge
         SimpleIconFactory sif = SimpleIconFactory.obtain(mContext);
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index e60f7fc..dd4409c 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -44,26 +44,37 @@
     private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
 
     // Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
-    public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 1;
-    public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 0;
-    public static final int CUJ_NOTIFICATION_SHADE_SCROLL_FLING = 0;
-    public static final int CUJ_NOTIFICATION_SHADE_ROW_EXPAND = 0;
-    public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = 0;
-    public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = 0;
-    public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = 0;
-    public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS = 0;
-    public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON = 0;
-    public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = 0;
-    public static final int CUJ_LAUNCHER_APP_CLOSE_TO_PIP = 0;
-    public static final int CUJ_LAUNCHER_QUICK_SWITCH = 0;
+    public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 0;
+    public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 1;
+    public static final int CUJ_NOTIFICATION_SHADE_SCROLL_FLING = 2;
+    public static final int CUJ_NOTIFICATION_SHADE_ROW_EXPAND = 3;
+    public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = 4;
+    public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = 5;
+    public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = 6;
+    public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS = 7;
+    public static final int CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON = 8;
+    public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = 9;
+    public static final int CUJ_LAUNCHER_APP_CLOSE_TO_PIP = 10;
+    public static final int CUJ_LAUNCHER_QUICK_SWITCH = 11;
 
     private static final int NO_STATSD_LOGGING = -1;
 
     // Used to convert CujType to InteractionType enum value for statsd logging.
     // Use NO_STATSD_LOGGING in case the measurement for a given CUJ should not be logged to statsd.
-    private static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = {
-            NO_STATSD_LOGGING,
+    @VisibleForTesting
+    public static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = {
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
+            NO_STATSD_LOGGING,
     };
 
     private static volatile InteractionJankMonitor sInstance;
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 095882e..60f1b44 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -36,7 +36,6 @@
 import com.android.server.NetworkManagementSocketTagger;
 
 import dalvik.system.RuntimeHooks;
-import dalvik.system.ThreadPrioritySetter;
 import dalvik.system.VMRuntime;
 
 import libcore.content.type.MimeMap;
@@ -208,7 +207,6 @@
      */
     public static void preForkInit() {
         if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
-        RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter());
         RuntimeInit.enableDdms();
         // TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e.
         // MimeMap.setDefault(DefaultMimeMapFactory.create());
@@ -221,35 +219,6 @@
         MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
     }
 
-    private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter {
-        // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc
-        private static final int[] NICE_VALUES = {
-            Process.THREAD_PRIORITY_LOWEST,  // 1 (MIN_PRIORITY)
-            Process.THREAD_PRIORITY_BACKGROUND + 6,
-            Process.THREAD_PRIORITY_BACKGROUND + 3,
-            Process.THREAD_PRIORITY_BACKGROUND,
-            Process.THREAD_PRIORITY_DEFAULT,  // 5 (NORM_PRIORITY)
-            Process.THREAD_PRIORITY_DEFAULT - 2,
-            Process.THREAD_PRIORITY_DEFAULT - 4,
-            Process.THREAD_PRIORITY_URGENT_DISPLAY + 3,
-            Process.THREAD_PRIORITY_URGENT_DISPLAY + 2,
-            Process.THREAD_PRIORITY_URGENT_DISPLAY  // 10 (MAX_PRIORITY)
-        };
-
-        @Override
-        public void setPriority(int nativeTid, int priority) {
-            // Check NICE_VALUES[] length first.
-            if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) {
-                throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length);
-            }
-            // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10).
-            if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
-                throw new IllegalArgumentException("Priority out of range: " + priority);
-            }
-            Process.setThreadPriority(nativeTid, NICE_VALUES[priority - Thread.MIN_PRIORITY]);
-        }
-    }
-
     @UnsupportedAppUsage
     protected static final void commonInit() {
         if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index a985965..5e20cd0 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -172,23 +172,11 @@
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
     /** Default external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT;
-    /** Read-only external storage should be mounted. */
-    public static final int MOUNT_EXTERNAL_READ = IVold.REMOUNT_MODE_READ;
-    /** Read-write external storage should be mounted. */
-    public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
-    /**
-     * Mount mode for apps that are already installed on the device before the isolated_storage
-     * feature is enabled.
-     */
-    public static final int MOUNT_EXTERNAL_LEGACY = IVold.REMOUNT_MODE_LEGACY;
     /**
      * Mount mode for package installers which should give them access to
      * all obb dirs in addition to their package sandboxes
      */
     public static final int MOUNT_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER;
-    /** Read-write external storage should be mounted instead of package sandbox */
-    public static final int MOUNT_EXTERNAL_FULL = IVold.REMOUNT_MODE_FULL;
-
     /** The lower file system should be bind mounted directly on external storage */
     public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;
 
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index ed07432..32b808a 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -380,16 +380,8 @@
                 mNiceName = getAssignmentValue(arg);
             } else if (arg.equals("--mount-external-default")) {
                 mMountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
-            } else if (arg.equals("--mount-external-read")) {
-                mMountExternal = Zygote.MOUNT_EXTERNAL_READ;
-            } else if (arg.equals("--mount-external-write")) {
-                mMountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
-            } else if (arg.equals("--mount-external-full")) {
-                mMountExternal = Zygote.MOUNT_EXTERNAL_FULL;
-            }  else if (arg.equals("--mount-external-installer")) {
+            } else if (arg.equals("--mount-external-installer")) {
                 mMountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
-            }  else if (arg.equals("--mount-external-legacy")) {
-                mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
             } else if (arg.equals("--mount-external-pass-through")) {
                 mMountExternal = Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
             } else if (arg.equals("--mount-external-android-writable")) {
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 50ba42f..ce3efd3 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -48,6 +48,10 @@
             Consts.TAG_WM),
     WM_DEBUG_LOCKTASK(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM),
+    WM_DEBUG_STATES(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_TASKS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
     WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM),
     WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1bf8efb..1419855 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1333,17 +1333,6 @@
     transaction->deferTransactionUntil_legacy(ctrl, barrier, frameNumber);
 }
 
-static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong transactionObj,
-        jlong nativeObject,
-        jlong surfaceObject, jlong frameNumber) {
-    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-
-    auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
-
-    transaction->deferTransactionUntil_legacy(ctrl, barrier, frameNumber);
-}
-
 static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject,
         jlong newParentObject) {
@@ -1699,8 +1688,6 @@
             (void*)nativeGetProtectedContentSupport },
     {"nativeDeferTransactionUntil", "(JJJJ)V",
             (void*)nativeDeferTransactionUntil },
-    {"nativeDeferTransactionUntilSurface", "(JJJJ)V",
-            (void*)nativeDeferTransactionUntilSurface },
     {"nativeReparentChildren", "(JJJ)V",
             (void*)nativeReparentChildren } ,
     {"nativeReparent", "(JJJ)V",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index e6bfecc..42aab6a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -326,31 +326,15 @@
 static FileDescriptorTable* gOpenFdTable = nullptr;
 
 // Must match values in com.android.internal.os.Zygote.
-// The order of entries here must be kept in sync with ExternalStorageViews array values.
+// Note that there are gaps in the constants:
+// This is to further keep the values consistent with IVold.aidl
 enum MountExternalKind {
-  MOUNT_EXTERNAL_NONE = 0,
-  MOUNT_EXTERNAL_DEFAULT = 1,
-  MOUNT_EXTERNAL_READ = 2,
-  MOUNT_EXTERNAL_WRITE = 3,
-  MOUNT_EXTERNAL_LEGACY = 4,
-  MOUNT_EXTERNAL_INSTALLER = 5,
-  MOUNT_EXTERNAL_FULL = 6,
-  MOUNT_EXTERNAL_PASS_THROUGH = 7,
-  MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
-  MOUNT_EXTERNAL_COUNT = 9
-};
-
-// The order of entries here must be kept in sync with MountExternalKind enum values.
-static const std::array<const std::string, MOUNT_EXTERNAL_COUNT> ExternalStorageViews = {
-  "",                     // MOUNT_EXTERNAL_NONE
-  "/mnt/runtime/default", // MOUNT_EXTERNAL_DEFAULT
-  "/mnt/runtime/read",    // MOUNT_EXTERNAL_READ
-  "/mnt/runtime/write",   // MOUNT_EXTERNAL_WRITE
-  "/mnt/runtime/write",   // MOUNT_EXTERNAL_LEGACY
-  "/mnt/runtime/write",   // MOUNT_EXTERNAL_INSTALLER
-  "/mnt/runtime/full",    // MOUNT_EXTERNAL_FULL
-  "/mnt/runtime/full",    // MOUNT_EXTERNAL_PASS_THROUGH (only used w/ FUSE)
-  "/mnt/runtime/full",    // MOUNT_EXTERNAL_ANDROID_WRITABLE (only used w/ FUSE)
+    MOUNT_EXTERNAL_NONE = 0,
+    MOUNT_EXTERNAL_DEFAULT = 1,
+    MOUNT_EXTERNAL_INSTALLER = 5,
+    MOUNT_EXTERNAL_PASS_THROUGH = 7,
+    MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
+    MOUNT_EXTERNAL_COUNT = 9
 };
 
 // Must match values in com.android.internal.os.Zygote.
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index d4d8772..d315ff2 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -205,9 +205,8 @@
     optional WindowStateProto input_method_input_target = 28;
     optional WindowStateProto input_method_control_target = 29;
     optional WindowStateProto current_focus = 30;
-    optional InsetsSourceProviderProto insets_source_provider = 31;
-    optional ImeInsetsSourceProviderProto ime_insets_source_provider = 32;
-    optional bool can_show_ime = 33;
+    optional ImeInsetsSourceProviderProto ime_insets_source_provider = 31;
+    optional bool can_show_ime = 32;
 }
 
 /* represents DisplayArea object */
@@ -527,6 +526,7 @@
 message ImeInsetsSourceProviderProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional WindowStateProto ime_target_from_ime = 1;
-    optional bool is_ime_layout_drawn = 2;
+    optional InsetsSourceProviderProto insets_source_provider = 1;
+    optional WindowStateProto ime_target_from_ime = 2;
+    optional bool is_ime_layout_drawn = 3;
 }
\ No newline at end of file
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 004b096..d289e00 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -124,6 +124,11 @@
         optional string originating_package_name = 2;
     }
 
+    message StatesProto {
+        optional bool is_startable = 1;
+        optional bool is_loading = 2;
+    }
+
     // Name of package. e.g. "com.android.providers.telephony".
     optional string name = 1;
     // UID for this package as assigned by Android OS.
@@ -145,4 +150,6 @@
     repeated UserInfoProto users = 9;
     // Where the request to install this package came from,
     optional InstallSourceProto install_source = 10;
+    // Whether the package is startable or is still loading
+    optional StatesProto states = 11;
 }
diff --git a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
index 2729e82..856d8da 100644
--- a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
+++ b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
@@ -65,8 +65,6 @@
         repeated ClientSideProto client = 1;
     }
 
-    /* todo: extract as a separate message to allow other dumps to use this as their client side
-        proto */
     /* groups together the dump from ime related client side classes */
     message ClientSideProto {
         optional int32 display_id = 1;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7247e4f..c8b8ef2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -42,6 +42,9 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_STARTABLE" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_UNSTARTABLE" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_LOADED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_ENABLE_ROLLBACK" />
     <protected-broadcast android:name="android.intent.action.CANCEL_ENABLE_ROLLBACK" />
     <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" />
@@ -1575,6 +1578,13 @@
     <permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows an application to install a LocationTimeZoneProvider into the
+         LocationTimeZoneProviderManager.
+         <p>Not for use by third-party applications.
+    -->
+    <permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
          This should only be used by HDMI-CEC service.
     -->
@@ -2712,7 +2722,7 @@
     <!-- Allows applications like settings to manage configuration associated with automatic time
          and time zone detection.
          <p>Not for use by third-party applications.
-         @hide
+         @SystemApi @hide
     -->
     <permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION"
         android:protectionLevel="signature|privileged" />
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 60f7a09..fac2f22 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -432,23 +432,17 @@
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
-    <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
-    <skip />
-    <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
-    <skip />
-    <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
-    <skip />
+    <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+    <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
-    <!-- no translation found for permdesc_camera (5240801376168647151) -->
-    <skip />
-    <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
-    <skip />
-    <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
-    <skip />
+    <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+    <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index ae3aaab..8497658 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -432,23 +432,17 @@
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
-    <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
-    <skip />
-    <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
-    <skip />
-    <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
-    <skip />
+    <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+    <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
-    <!-- no translation found for permdesc_camera (5240801376168647151) -->
-    <skip />
-    <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
-    <skip />
-    <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
-    <skip />
+    <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+    <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 52dcf97..12881e7 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -432,23 +432,17 @@
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
-    <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
-    <skip />
-    <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
-    <skip />
-    <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
-    <skip />
+    <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+    <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
-    <!-- no translation found for permdesc_camera (5240801376168647151) -->
-    <skip />
-    <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
-    <skip />
-    <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
-    <skip />
+    <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+    <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 2f7f271..cb2eb7a 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -432,23 +432,17 @@
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"change your audio settings"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Allows the app to modify global audio settings such as volume and which speaker is used for output."</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"record audio"</string>
-    <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
-    <skip />
-    <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
-    <skip />
-    <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
-    <skip />
+    <string name="permdesc_recordAudio" msgid="5857246765327514062">"This app can record audio using the microphone while the app is in use."</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"record audio in the background"</string>
+    <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"This app can record audio using the microphone at any time."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"send commands to the SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Allows the app to send commands to the SIM. This is very dangerous."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"recognise physical activity"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"This app can recognise your physical activity."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"take pictures and videos"</string>
-    <!-- no translation found for permdesc_camera (5240801376168647151) -->
-    <skip />
-    <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
-    <skip />
-    <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
-    <skip />
+    <string name="permdesc_camera" msgid="5240801376168647151">"This app can take pictures and record videos using the camera while the app is in use."</string>
+    <string name="permlab_backgroundCamera" msgid="7549917926079731681">"take pictures and videos in the background"</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"This app can take pictures and record videos using the camera at any time."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"Grant an application or service access to system cameras to take pictures and videos"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 8f017f9..5750e50 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -432,23 +432,17 @@
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎change your audio settings‎‏‎‎‏‎"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎Allows the app to modify global audio settings such as volume and which speaker is used for output.‎‏‎‎‏‎"</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎record audio‎‏‎‎‏‎"</string>
-    <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
-    <skip />
-    <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
-    <skip />
-    <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
-    <skip />
+    <string name="permdesc_recordAudio" msgid="5857246765327514062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎This app can record audio using the microphone while the app is in use.‎‏‎‎‏‎"</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎record audio in the background‎‏‎‎‏‎"</string>
+    <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎This app can record audio using the microphone at any time.‎‏‎‎‏‎"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎send commands to the SIM‎‏‎‎‏‎"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎Allows the app to send commands to the SIM. This is very dangerous.‎‏‎‎‏‎"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎recognize physical activity‎‏‎‎‏‎"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎This app can recognize your physical activity.‎‏‎‎‏‎"</string>
     <string name="permlab_camera" msgid="6320282492904119413">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎take pictures and videos‎‏‎‎‏‎"</string>
-    <!-- no translation found for permdesc_camera (5240801376168647151) -->
-    <skip />
-    <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
-    <skip />
-    <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
-    <skip />
+    <string name="permdesc_camera" msgid="5240801376168647151">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎This app can take pictures and record videos using the camera while the app is in use.‎‏‎‎‏‎"</string>
+    <string name="permlab_backgroundCamera" msgid="7549917926079731681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‎‏‎take pictures and videos in the background‎‏‎‎‏‎"</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎This app can take pictures and record videos using the camera at any time.‎‏‎‎‏‎"</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎Allow an application or service access to system cameras to take pictures and videos‎‏‎‎‏‎"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well‎‏‎‎‏‎"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎Allow an application or service to receive callbacks about camera devices being opened or closed.‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index b327342..7b376ff 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1632,12 +1632,10 @@
     <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"सिफारिस तहभन्दा आवाज ठुलो गर्नुहुन्छ?\n\nलामो समय सम्म उच्च आवाजमा सुन्दा तपाईँको सुन्ने शक्तिलाई हानी गर्न सक्छ।"</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"पहुँच सम्बन्धी सर्टकट प्रयोग गर्ने हो?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"यो सर्टकट सक्रिय हुँदा, ३ सेकेन्डसम्म दुवै भोल्युम बटन थिच्नुले पहुँचसम्बन्धी कुनै सुविधा सुरु गर्ने छ।"</string>
-    <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (3135860819356676426) -->
-    <skip />
+    <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"सर्वसुलभता कायम गर्ने सुविधाहरू प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
     <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"केही सेकेन्डसम्म दुवै भोल्युम बटन थिचिराख्नुभयो भने पहुँचसम्बन्धी सुविधाहरू सक्रिय हुन्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nहालका सुविधाहरू:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतपाईं सेटिङ &gt; पहुँचमा गएर चयन गरिएका सुविधाहरू परिवर्तन गर्न सक्नुहुन्छ।"</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
-    <!-- no translation found for accessibility_shortcut_single_service_warning_title (1909518473488345266) -->
-    <skip />
+    <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"केही सेकेन्डसम्म दुवै भोल्युम बटन थिचिराख्नुले <xliff:g id="SERVICE">%1$s</xliff:g> नामक पहुँचसम्बन्धी सुविधा  सक्रिय गर्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nतपाईं सेटिङ &gt; पहुँचमा गई यो सर्टकटमार्फत अर्को सुविधा खुल्ने बनाउन सक्नुहुन्छ।"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"सक्रिय गरियोस्"</string>
     <string name="accessibility_shortcut_off" msgid="3651336255403648739">"सक्रिय नगरियोस्"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f09e7b0..450fddb 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -432,23 +432,17 @@
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"alterar as suas configurações de áudio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que o app modifique configurações de áudio globais como volume e alto-falantes de saída."</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"gravar áudio"</string>
-    <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
-    <skip />
-    <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
-    <skip />
-    <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
-    <skip />
+    <string name="permdesc_recordAudio" msgid="5857246765327514062">"Enquanto está sendo usado, este app pode gravar áudio usando o microfone."</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar áudio em segundo plano"</string>
+    <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o chip"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer atividade física"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Este app pode reconhecer sua atividade física."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"tirar fotos e gravar vídeos"</string>
-    <!-- no translation found for permdesc_camera (5240801376168647151) -->
-    <skip />
-    <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
-    <skip />
-    <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
-    <skip />
+    <string name="permdesc_camera" msgid="5240801376168647151">"Enquanto está sendo usado, este app pode tirar fotos e gravar vídeos usando a câmera."</string>
+    <string name="permlab_backgroundCamera" msgid="7549917926079731681">"tirar fotos e gravar vídeos em segundo plano"</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que um aplicativo ou serviço acesse as câmeras do sistema para tirar fotos e gravar vídeos"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"Esse app do sistema ou com privilégios pode tirar fotos e gravar vídeos a qualquer momento usando a câmera do sistema. É necessário que o app tenha também a permissão android.permission.CAMERA"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f09e7b0..450fddb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -432,23 +432,17 @@
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"alterar as suas configurações de áudio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que o app modifique configurações de áudio globais como volume e alto-falantes de saída."</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"gravar áudio"</string>
-    <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
-    <skip />
-    <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
-    <skip />
-    <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
-    <skip />
+    <string name="permdesc_recordAudio" msgid="5857246765327514062">"Enquanto está sendo usado, este app pode gravar áudio usando o microfone."</string>
+    <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar áudio em segundo plano"</string>
+    <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o chip"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer atividade física"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Este app pode reconhecer sua atividade física."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"tirar fotos e gravar vídeos"</string>
-    <!-- no translation found for permdesc_camera (5240801376168647151) -->
-    <skip />
-    <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
-    <skip />
-    <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
-    <skip />
+    <string name="permdesc_camera" msgid="5240801376168647151">"Enquanto está sendo usado, este app pode tirar fotos e gravar vídeos usando a câmera."</string>
+    <string name="permlab_backgroundCamera" msgid="7549917926079731681">"tirar fotos e gravar vídeos em segundo plano"</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que um aplicativo ou serviço acesse as câmeras do sistema para tirar fotos e gravar vídeos"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"Esse app do sistema ou com privilégios pode tirar fotos e gravar vídeos a qualquer momento usando a câmera do sistema. É necessário que o app tenha também a permissão android.permission.CAMERA"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fc2fd35..d074960 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1325,7 +1325,7 @@
     <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Отмена"</string>
     <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Запомнить выбор"</string>
     <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"Это можно изменить позже в разделе настроек \"Приложения\"."</string>
-    <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Всегда разрешать"</string>
+    <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Разрешать всегда"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"Не разрешать"</string>
     <string name="sim_removed_title" msgid="5387212933992546283">"SIM-карта удалена"</string>
     <string name="sim_removed_message" msgid="9051174064474904617">"Пока вы не вставите действующую SIM-карту, мобильная сеть будет недоступна."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cc4d306..71e9ed7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1578,6 +1578,16 @@
          config_timeZoneRulesUpdateTrackingEnabled are true.] -->
     <integer name="config_timeZoneRulesCheckRetryCount">5</integer>
 
+    <!-- Whether to enable primary location time zone provider overlay which allows the primary
+         location time zone provider to be replaced by an app at run-time. When disabled, only the
+         config_primaryLocationTimeZoneProviderPackageName package will be searched for the primary
+         location time zone provider, otherwise any system package is eligible. Anyone who wants to
+         disable the overlay mechanism can set it to false. -->
+    <bool name="config_enablePrimaryLocationTimeZoneOverlay" translatable="false">false</bool>
+    <!-- Package name providing the primary location time zone provider. Used only when
+         config_enablePrimaryLocationTimeZoneOverlay is false. -->
+    <string name="config_primaryLocationTimeZoneProviderPackageName" translatable="false">@null</string>
+
     <!-- Whether to enable network location overlay which allows network location provider to be
          replaced by an app at run-time. When disabled, only the
          config_networkLocationProviderPackageName package will be searched for network location
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 812e895..3e59549 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2158,6 +2158,8 @@
   <java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
   <java-symbol type="string" name="config_persistentDataPackageName" />
   <java-symbol type="string" name="config_deviceConfiguratorPackageName" />
+  <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
+  <java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index b669cc6..a9cfd28 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -17,8 +17,10 @@
 package com.android.internal.jank;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_TO_STATSD_INTERACTION_TYPE;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -45,6 +47,13 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
 @SmallTest
 public class InteractionJankMonitorTest {
     private ViewAttachTestActivity mActivity;
@@ -138,4 +147,27 @@
         verify(tracker).cancel();
     }
 
+    @Test
+    public void testCujTypeEnumCorrectlyDefined() throws Exception {
+        List<Field> cujEnumFields =
+                Arrays.stream(InteractionJankMonitor.class.getDeclaredFields())
+                        .filter(field -> field.getName().startsWith("CUJ_")
+                                && Modifier.isStatic(field.getModifiers())
+                                && field.getType() == int.class)
+                        .collect(Collectors.toList());
+
+        HashSet<Integer> allValues = new HashSet<>();
+        for (Field field : cujEnumFields) {
+            int fieldValue = field.getInt(null);
+            assertWithMessage(
+                    "Field %s must have a mapping to a value in CUJ_TO_STATSD_INTERACTION_TYPE",
+                    field.getName())
+                    .that(fieldValue < CUJ_TO_STATSD_INTERACTION_TYPE.length)
+                    .isTrue();
+            assertWithMessage("All CujType values must be unique. Field %s repeats existing value.",
+                    field.getName())
+                    .that(allValues.add(fieldValue))
+                    .isTrue();
+        }
+    }
 }
diff --git a/data/etc/com.android.storagemanager.xml b/data/etc/com.android.storagemanager.xml
index e85a82c..a1635fe 100644
--- a/data/etc/com.android.storagemanager.xml
+++ b/data/etc/com.android.storagemanager.xml
@@ -22,5 +22,6 @@
         <permission name="android.permission.PACKAGE_USAGE_STATS"/>
         <permission name="android.permission.USE_RESERVED_DISK"/>
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+        <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index c53ea87..29c8de6 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -49,6 +49,18 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-2062338592": {
+      "message": "Looking for task of %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-2054442123": {
+      "message": "Setting Intent of %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-2049725903": {
       "message": "Task back pressed on root taskId=%d",
       "level": "VERBOSE",
@@ -103,6 +115,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
     },
+    "-1977793524": {
+      "message": "moveStackToDisplay: moving stackId=%d to displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-1976930686": {
       "message": "Attempted to add Accessibility overlay window with bad token %s.  Aborting.",
       "level": "WARN",
@@ -163,6 +181,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
     },
+    "-1890326172": {
+      "message": "no-history finish of %s on new resume",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-1884933373": {
       "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
       "level": "INFO",
@@ -199,6 +223,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
+    "-1861864501": {
+      "message": "resumeTopActivityLocked: Going to sleep and all paused",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-1847087163": {
       "message": "TRANSIT_TASK_OPEN_BEHIND,  adding %s to mOpeningApps",
       "level": "DEBUG",
@@ -259,6 +289,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "-1768090656": {
+      "message": "Re-launching after pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-1750206390": {
       "message": "Exception thrown when creating surface for client %s (%s). %s",
       "level": "WARN",
@@ -295,6 +331,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-1704402370": {
+      "message": "resetTaskIntendedTask: calling finishActivity on %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
     "-1699018375": {
       "message": "Adding activity %s to task %s callers: %s",
       "level": "INFO",
@@ -307,6 +349,12 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-1679411993": {
+      "message": "setVr2dDisplayId called for: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-1670695197": {
       "message": "Attempted to add presentation window to a non-suitable display.  Aborting.",
       "level": "WARN",
@@ -319,6 +367,18 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1655805455": {
+      "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-1647332198": {
+      "message": "remove RecentTask %s when finishing user %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RecentTasks.java"
+    },
     "-1638958146": {
       "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
       "level": "INFO",
@@ -337,6 +397,24 @@
       "group": "WM_DEBUG_LOCKTASK",
       "at": "com\/android\/server\/wm\/LockTaskController.java"
     },
+    "-1613096551": {
+      "message": "Top resumed state released %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
+    "-1607026519": {
+      "message": "Ready to stop: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
+    "-1601745126": {
+      "message": "Launch on display check: allow launch for owner of the display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "-1598452494": {
       "message": "activityDestroyedLocked: r=%s",
       "level": "DEBUG",
@@ -355,6 +433,18 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-1585311008": {
+      "message": "Bring to front target: %s from %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
+    "-1575977269": {
+      "message": "Skipping %s: mismatch root %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "-1568331821": {
       "message": "Enabling listeners",
       "level": "VERBOSE",
@@ -367,6 +457,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-1558137010": {
+      "message": "Config is relaunching invisible activity %s called by %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1554521902": {
       "message": "showInsets(ime) was requested by different window: %s ",
       "level": "WARN",
@@ -433,6 +529,18 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
+    "-1492696222": {
+      "message": "App died during pause, not stopping: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-1474292612": {
+      "message": "Could not find task for id: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-1471946192": {
       "message": "Marking app token %s with replacing child windows.",
       "level": "DEBUG",
@@ -463,6 +571,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "-1432963966": {
+      "message": "Moving to DESTROYING: %s (destroy requested)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1427184084": {
       "message": "addWindow: New client %s: window=%s Callers=%s",
       "level": "VERBOSE",
@@ -499,6 +613,12 @@
       "group": "WM_DEBUG_SYNC_ENGINE",
       "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
     },
+    "-1376035390": {
+      "message": "No task found",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "-1375751630": {
       "message": "  --- Start combine pass ---",
       "level": "VERBOSE",
@@ -541,12 +661,36 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-1305966693": {
+      "message": "Sending position change to %s, onTop: %b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1305791032": {
+      "message": "Moving to STOPPED: %s (stop complete)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1305755880": {
       "message": "Initial config: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "-1304806505": {
+      "message": "Starting new activity %s in new task %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
+    "-1295684101": {
+      "message": "Launch on display check: no caller info, skip check",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "-1292329638": {
       "message": "Added starting %s: startingWindow=%s startingView=%s",
       "level": "VERBOSE",
@@ -601,12 +745,30 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "-1198579104": {
+      "message": "Pushing next activity %s out to target's task %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "-1193946201": {
+      "message": "Can't report activity position update - client not running, activityRecord=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1176488860": {
       "message": "SURFACE isSecure=%b: %s",
       "level": "INFO",
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
     },
+    "-1164930508": {
+      "message": "Moving to RESUMED: %s (starting new instance) callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-1156118957": {
       "message": "Updated config=%s",
       "level": "DEBUG",
@@ -631,6 +793,12 @@
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-1136139407": {
+      "message": "no-history finish of %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1130891072": {
       "message": "Orientation continue waiting for draw in %s",
       "level": "VERBOSE",
@@ -697,12 +865,24 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-1084548141": {
+      "message": "Launch on display check: allow launch any on display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "-1076978367": {
       "message": "thawRotation: mRotation=%d",
       "level": "VERBOSE",
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1066383762": {
+      "message": "Sleep still waiting to pause %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-1060365734": {
       "message": "Attempted to add QS dialog window with bad token %s.  Aborting.",
       "level": "WARN",
@@ -727,12 +907,30 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1022146708": {
+      "message": "Skipping %s: mismatch activity type",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-1016578046": {
+      "message": "Moving to %s Relaunching %s callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1009117329": {
       "message": "isFetchingAppTransitionSpecs=true",
       "level": "VERBOSE",
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
+    "-1003060523": {
+      "message": "Finish needs to pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-993378225": {
       "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s",
       "level": "VERBOSE",
@@ -751,6 +949,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
     },
+    "-937498525": {
+      "message": "Executing finish of failed to pause activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-930893991": {
       "message": "Set sync ready, syncId=%d",
       "level": "VERBOSE",
@@ -775,6 +979,18 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "-926231510": {
+      "message": "State unchanged from:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-917215012": {
+      "message": "%s: caller %d is using old GET_TASKS but privileged; allowing",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "-916108501": {
       "message": "Adding %s to %s",
       "level": "VERBOSE",
@@ -787,18 +1003,36 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-903853754": {
+      "message": "pauseBackStacks: stack=%s mResumedActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
     "-883738232": {
       "message": "Adding more than one toast window for UID at a time.",
       "level": "WARN",
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-877494781": {
+      "message": "Start pushing activity %s out to bottom task %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
     "-874446906": {
       "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
       "level": "INFO",
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-866966979": {
+      "message": "Moving to PAUSED: %s (starting in paused state)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "-861859917": {
       "message": "Attempted to add window to a display that does not exist: %d. Aborting.",
       "level": "WARN",
@@ -841,6 +1075,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-814760297": {
+      "message": "Looking for task of %s in %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "-809771899": {
       "message": "findFocusedWindow: Reached focused app=%s",
       "level": "VERBOSE",
@@ -871,6 +1111,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-775004869": {
+      "message": "Not a match: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "-771177730": {
       "message": "Removing focused app token:%s displayId=%d",
       "level": "VERBOSE",
@@ -901,12 +1147,24 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-729530161": {
+      "message": "Moving to DESTROYED: %s (no app)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-716565534": {
       "message": "moveActivityStackToFront: unfocusable activity=%s",
       "level": "DEBUG",
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-705939410": {
+      "message": "Waiting for pause to complete...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-703543418": {
       "message": "      check sibling %s",
       "level": "VERBOSE",
@@ -925,6 +1183,12 @@
       "group": "WM_DEBUG_SYNC_ENGINE",
       "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
     },
+    "-672228342": {
+      "message": "resumeTopActivityLocked: Top activity resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-668956537": {
       "message": "  THUMBNAIL %s: CREATE",
       "level": "INFO",
@@ -943,6 +1207,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "-650261962": {
+      "message": "Sleep needs to pause %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-639305784": {
       "message": "Could not report config changes to the window token client.",
       "level": "WARN",
@@ -979,6 +1249,18 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-606328116": {
+      "message": "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-596163537": {
+      "message": "Waiting for top state to be released by %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "-593535526": {
       "message": "Binding proc %s with config %s",
       "level": "VERBOSE",
@@ -997,6 +1279,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
+    "-571686216": {
+      "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "-561092364": {
       "message": "onPointerDownOutsideFocusLocked called on %s",
       "level": "INFO",
@@ -1027,12 +1315,24 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowAnimator.java"
     },
+    "-533690126": {
+      "message": "resumeTopActivityLocked: Resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-532081937": {
       "message": "  Commit activity becoming invisible: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-527683022": {
+      "message": "resumeTopActivityLocked: Skip resume: some activity pausing.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-519504830": {
       "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
       "level": "VERBOSE",
@@ -1117,6 +1417,18 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
+    "-427457280": {
+      "message": "App died while pausing: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-417514857": {
+      "message": "Key dispatch not paused for screen off",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-415865166": {
       "message": "findFocusedWindow: Found new focus @ %s",
       "level": "VERBOSE",
@@ -1135,6 +1447,18 @@
       "group": "WM_DEBUG_CONTAINERS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-401029526": {
+      "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-399343789": {
+      "message": "Skipping %s: different user",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "-395922585": {
       "message": "InsetsSource setWin %s",
       "level": "DEBUG",
@@ -1183,6 +1507,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
     },
+    "-332679827": {
+      "message": "resumeNextFocusableActivityWhenStackIsEmpty: %s, go home",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-324085783": {
       "message": "SURFACE CROP %s: %s",
       "level": "INFO",
@@ -1225,12 +1555,30 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-300896109": {
+      "message": "moveTaskToStack: moving task=%d to stackId=%d toTop=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-279436615": {
+      "message": "Moving to PAUSING: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-272719931": {
       "message": "startLockTaskModeLocked: %s",
       "level": "WARN",
       "group": "WM_DEBUG_LOCKTASK",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "-262984451": {
+      "message": "Relaunch failed %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-260960989": {
       "message": "Removing and adding activity %s to stack at top callers=%s",
       "level": "INFO",
@@ -1249,6 +1597,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-234244777": {
+      "message": "Activity config changed during resume: %s, new next: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-198463978": {
       "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
       "level": "VERBOSE",
@@ -1273,6 +1627,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "-172326720": {
+      "message": "Saving icicle of %s: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-168799453": {
       "message": "Allowing features %d:0x%s",
       "level": "WARN",
@@ -1291,6 +1651,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
+    "-118786523": {
+      "message": "Resume failed; resetting state to %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "-116086365": {
       "message": "******************** ENABLING SCREEN!",
       "level": "INFO",
@@ -1351,6 +1717,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
     },
+    "-21399771": {
+      "message": "activity %s already destroying, skipping request with reason:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-7343917": {
       "message": "onAnimationFinished(): targetStack=%s targetActivity=%s mRestoreTargetBehindStack=%s",
       "level": "DEBUG",
@@ -1411,6 +1783,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "51927339": {
+      "message": "Skipping %s: voice session",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "73987756": {
       "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
       "level": "INFO",
@@ -1429,12 +1807,24 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "86989930": {
+      "message": "setTaskWindowingMode: moving task=%d to windowingMode=%d toTop=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "91350919": {
       "message": "Attempted to set IME flag to a display that does not exist: %d",
       "level": "WARN",
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "94402792": {
+      "message": "Moving to RESUMED: %s (in existing)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "95216706": {
       "message": "hideIme target: %s ",
       "level": "DEBUG",
@@ -1537,6 +1927,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
+    "189628502": {
+      "message": "Moving to STOPPING: %s (stop requested)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "194124419": {
       "message": "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d",
       "level": "DEBUG",
@@ -1657,6 +2053,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "306524472": {
+      "message": "Stop failed; moving to STOPPED: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "309039362": {
       "message": "SURFACE MATRIX [%f,%f,%f,%f]: %s",
       "level": "INFO",
@@ -1729,6 +2131,12 @@
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "397382873": {
+      "message": "Moving to PAUSED: %s %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "399841913": {
       "message": "SURFACE RECOVER DESTROY: %s",
       "level": "INFO",
@@ -1783,6 +2191,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "485170982": {
+      "message": "Not finishing noHistory %s on stop because we're just sleeping",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "487621047": {
       "message": "DisplayArea vanished name=%s",
       "level": "VERBOSE",
@@ -1849,6 +2263,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
     },
+    "579298675": {
+      "message": "Moving to DESTROYED: %s (removed from history)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "585096182": {
       "message": "SURFACE isColorSpaceAgnostic=%b: %s",
       "level": "INFO",
@@ -1969,6 +2389,12 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "674932310": {
+      "message": "Setting Intent of %s to target %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "685047360": {
       "message": "Resizing window %s",
       "level": "VERBOSE",
@@ -1993,12 +2419,24 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "709500946": {
+      "message": "resumeTopActivityLocked: Skip resume: need to start pausing",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "715749922": {
       "message": "Allowlisting %d:%s",
       "level": "WARN",
       "group": "WM_DEBUG_LOCKTASK",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "726205185": {
+      "message": "Moving to DESTROYED: %s (destroy skipped)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "736692676": {
       "message": "Config is relaunching %s",
       "level": "VERBOSE",
@@ -2083,6 +2521,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "864551564": {
+      "message": "Launch on display check: disallow activity embedding without permission.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "869266572": {
       "message": "Removing activity %s from stack, reason= %s callers=%s",
       "level": "INFO",
@@ -2101,12 +2545,30 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "875196661": {
+      "message": "Skipping stack: (mismatch activity\/stack) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
     "892244061": {
       "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
       "level": "INFO",
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "895158150": {
+      "message": "allPausedActivitiesComplete: r=%s state=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "897964776": {
+      "message": "Complete pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "898863925": {
       "message": "Attempted to add QS dialog window with unknown token %s.  Aborting.",
       "level": "WARN",
@@ -2161,6 +2623,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "988389910": {
+      "message": "resumeTopActivityLocked: Pausing %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "996960396": {
       "message": "Starting Transition %d",
       "level": "VERBOSE",
@@ -2173,12 +2641,30 @@
       "group": "WM_DEBUG_SYNC_ENGINE",
       "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
     },
+    "1001509841": {
+      "message": "Auto-PIP allowed, entering PIP mode directly: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "1001904964": {
       "message": "***** BOOT TIMEOUT: forcing display enabled",
       "level": "WARN",
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1015542198": {
+      "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
+    "1023413388": {
+      "message": "Finish waiting for pause of: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1040675582": {
       "message": "Can't report activity configuration update - client not running, activityRecord=%s",
       "level": "WARN",
@@ -2191,6 +2677,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1047769218": {
+      "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1049367566": {
       "message": "Sending to proc %s new config %s",
       "level": "VERBOSE",
@@ -2203,6 +2695,12 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "1068803972": {
+      "message": "Activity paused: token=%s, timeout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1073230342": {
       "message": "startAnimation",
       "level": "DEBUG",
@@ -2221,6 +2719,12 @@
       "group": "WM_SHOW_SURFACE_ALLOC",
       "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
     },
+    "1098891625": {
+      "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "1112047265": {
       "message": "finishDrawingWindow: %s mDrawState=%s",
       "level": "DEBUG",
@@ -2239,6 +2743,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1126328412": {
+      "message": "Scheduling idle now: forceIdle=%b immediate=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1140424002": {
       "message": "Finished screen turning on...",
       "level": "INFO",
@@ -2263,12 +2773,24 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "1192413464": {
+      "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "1208313423": {
       "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d",
       "level": "WARN",
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1217926207": {
+      "message": "Activity not running, resuming next.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "1219600119": {
       "message": "addWindow: win=%s Callers=%s",
       "level": "DEBUG",
@@ -2305,12 +2827,24 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1270792394": {
+      "message": "Resumed after relaunch %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1288731814": {
       "message": "WindowState.hideLw: setting mFocusMayChange true",
       "level": "INFO",
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "1316533291": {
+      "message": "State movement: %s from:%s to:%s reason:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1325649102": {
       "message": "Bad requesting window %s",
       "level": "WARN",
@@ -2353,6 +2887,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "1364126018": {
+      "message": "Resumed activity; dropping state of: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1364498663": {
       "message": "notifyAppResumed: wasStopped=%b %s",
       "level": "VERBOSE",
@@ -2503,6 +3043,12 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "1557732761": {
+      "message": "For Intent %s bringing to top: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "1563755163": {
       "message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
       "level": "WARN",
@@ -2527,12 +3073,24 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/WindowContainer.java"
     },
+    "1585450696": {
+      "message": "resumeTopActivityLocked: Restarting %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "1589610525": {
       "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
+    "1610646518": {
+      "message": "Enqueueing pending finish: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1628345525": {
       "message": "Now opening app %s",
       "level": "VERBOSE",
@@ -2593,6 +3151,18 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1696210756": {
+      "message": "Launch on display check: allow launch on public display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
+    "1706082525": {
+      "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "1720229827": {
       "message": "Creating animation bounds layer",
       "level": "INFO",
@@ -2659,6 +3229,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/TransitionController.java"
     },
+    "1804435108": {
+      "message": "allResumedActivitiesIdle: stack=%d %s not idle",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "1822843721": {
       "message": "Aborted starting %s: startingData=%s",
       "level": "VERBOSE",
@@ -2695,6 +3271,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1837992242": {
+      "message": "Executing finish of activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "1853793312": {
       "message": "Notify removed startingWindow %s",
       "level": "VERBOSE",
@@ -2713,12 +3295,24 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1884961873": {
+      "message": "Sleep still need to stop %d activities",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "1891501279": {
       "message": "cancelAnimation(): reason=%s",
       "level": "DEBUG",
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "1894239744": {
+      "message": "Enqueueing pending pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "1903353011": {
       "message": "notifyAppStopped: %s",
       "level": "VERBOSE",
@@ -2749,6 +3343,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
+    "1947936538": {
+      "message": "Found matching class!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "1964565370": {
       "message": "Starting remote animation",
       "level": "INFO",
@@ -2827,12 +3427,24 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
+    "2034714267": {
+      "message": "Launch on display check: allow launch for caller present on the display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStackSupervisor.java"
+    },
     "2034780299": {
       "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:",
       "level": "INFO",
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "2039056415": {
+      "message": "Found matching affinity candidate!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
     "2045641491": {
       "message": "Checking %d opening apps (frozen=%b timeout=%b)...",
       "level": "VERBOSE",
@@ -2881,6 +3493,12 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "2117696413": {
+      "message": "moveTaskToFront: moving taskId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "2119122320": {
       "message": "setInputMethodTarget %s",
       "level": "INFO",
@@ -2964,12 +3582,18 @@
     "WM_DEBUG_STARTING_WINDOW": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_STATES": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_SWITCH": {
       "tag": "WindowManager"
     },
     "WM_DEBUG_SYNC_ENGINE": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_TASKS": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_WINDOW_MOVEMENT": {
       "tag": "WindowManager"
     },
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java
new file mode 100644
index 0000000..9c84f50
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.bugpatterns.android.TargetSdkChecker.binaryTreeExact;
+import static com.google.errorprone.matchers.FieldMatchers.anyFieldInClass;
+import static com.google.errorprone.matchers.FieldMatchers.staticField;
+import static com.google.errorprone.matchers.Matchers.allOf;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.anything;
+import static com.google.errorprone.matchers.Matchers.kindIs;
+import static com.google.errorprone.matchers.Matchers.not;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.BinaryTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.BinaryTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.Tree.Kind;
+
+/**
+ * Each SDK level often has dozens of different behavior changes, which can be
+ * difficult for large app developers to adjust to during preview or beta
+ * releases. For this reason, {@code android.app.compat.CompatChanges} was
+ * introduced as a new best-practice for adding behavior changes.
+ * <p>
+ * During a preview or beta release, developers can temporarily opt-out of each
+ * individual change to aid debugging. This opt-out is only available during
+ * preview of beta releases, and cannot be adjusted on finalized builds.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+    name = "AndroidFrameworkCompatChange",
+    summary = "Verifies that behavior changes use the modern compatibility framework",
+    severity = WARNING)
+public final class CompatChangeChecker extends BugChecker implements BinaryTreeMatcher {
+    private static final Matcher<ExpressionTree> VERSION_CODE =
+            anyFieldInClass("android.os.Build.VERSION_CODES");
+
+    // Ship has already sailed on these SDK levels; not worth fixing
+    private static final Matcher<ExpressionTree> LEGACY_VERSION_CODE = anyOf(
+            staticField("android.os.Build.VERSION_CODES", "BASE"),
+            staticField("android.os.Build.VERSION_CODES", "BASE_1_1"),
+            staticField("android.os.Build.VERSION_CODES", "CUPCAKE"),
+            staticField("android.os.Build.VERSION_CODES", "DONUT"),
+            staticField("android.os.Build.VERSION_CODES", "ECLAIR"),
+            staticField("android.os.Build.VERSION_CODES", "ECLAIR_0_1"),
+            staticField("android.os.Build.VERSION_CODES", "ECLAIR_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "FROYO"),
+            staticField("android.os.Build.VERSION_CODES", "GINGERBREAD"),
+            staticField("android.os.Build.VERSION_CODES", "GINGERBREAD_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "HONEYCOMB"),
+            staticField("android.os.Build.VERSION_CODES", "HONEYCOMB_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "HONEYCOMB_MR2"),
+            staticField("android.os.Build.VERSION_CODES", "ICE_CREAM_SANDWICH"),
+            staticField("android.os.Build.VERSION_CODES", "ICE_CREAM_SANDWICH_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "JELLY_BEAN"),
+            staticField("android.os.Build.VERSION_CODES", "JELLY_BEAN_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "JELLY_BEAN_MR2"),
+            staticField("android.os.Build.VERSION_CODES", "KITKAT"),
+            staticField("android.os.Build.VERSION_CODES", "KITKAT_WATCH"),
+            staticField("android.os.Build.VERSION_CODES", "L"),
+            staticField("android.os.Build.VERSION_CODES", "LOLLIPOP"),
+            staticField("android.os.Build.VERSION_CODES", "LOLLIPOP_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "M"),
+            staticField("android.os.Build.VERSION_CODES", "N"),
+            staticField("android.os.Build.VERSION_CODES", "N_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "O"),
+            staticField("android.os.Build.VERSION_CODES", "O_MR1"),
+            staticField("android.os.Build.VERSION_CODES", "P"),
+            staticField("android.os.Build.VERSION_CODES", "Q"),
+            staticField("android.os.Build.VERSION_CODES", "R"));
+
+    private static final Matcher<ExpressionTree> R_VERSION_CODE =
+            staticField("android.os.Build.VERSION_CODES", "R");
+
+    private static final Matcher<ExpressionTree> CUR_DEVELOPMENT_VERSION_CODE =
+            staticField("android.os.Build.VERSION_CODES", "CUR_DEVELOPMENT");
+
+    private static final Matcher<ExpressionTree> MODERN_VERSION_CODE =
+            allOf(VERSION_CODE, not(LEGACY_VERSION_CODE), not(CUR_DEVELOPMENT_VERSION_CODE));
+
+    private static final Matcher<ExpressionTree> BOOLEAN_OPERATOR = anyOf(
+            kindIs(Kind.LESS_THAN), kindIs(Kind.LESS_THAN_EQUAL),
+            kindIs(Kind.GREATER_THAN), kindIs(Kind.GREATER_THAN_EQUAL),
+            kindIs(Kind.EQUAL_TO), kindIs(Kind.NOT_EQUAL_TO));
+
+    private static final Matcher<BinaryTree> INVALID = anyOf(
+            allOf(BOOLEAN_OPERATOR, binaryTreeExact(MODERN_VERSION_CODE, anything())),
+            allOf(BOOLEAN_OPERATOR, binaryTreeExact(anything(), MODERN_VERSION_CODE)),
+            allOf(kindIs(Kind.GREATER_THAN), binaryTreeExact(anything(), R_VERSION_CODE)),
+            allOf(kindIs(Kind.LESS_THAN), binaryTreeExact(R_VERSION_CODE, anything())));
+
+    @Override
+    public Description matchBinary(BinaryTree tree, VisitorState state) {
+        if (INVALID.matches(tree, state)) {
+            return buildDescription(tree)
+                    .setMessage("Behavior changes should use CompatChanges.isChangeEnabled() "
+                            + "instead of direct SDK checks to ease developer transitions; "
+                            + "see go/compat-framework for more details")
+                    .build();
+
+        }
+        return Description.NO_MATCH;
+    }
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
index 232cf3f..e1ebf42 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
@@ -89,7 +89,7 @@
         return Description.NO_MATCH;
     }
 
-    private static Matcher<BinaryTree> binaryTreeExact(Matcher<ExpressionTree> left,
+    static Matcher<BinaryTree> binaryTreeExact(Matcher<ExpressionTree> left,
             Matcher<ExpressionTree> right) {
         return new Matcher<BinaryTree>() {
             @Override
diff --git a/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java b/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
index 46f0fb2..08969d6 100644
--- a/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
+++ b/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
@@ -36,7 +36,8 @@
     return new FieldReferenceMatcher() {
       @Override
       boolean classIsAppropriate(ClassSymbol classSymbol) {
-        return classSymbol.getQualifiedName().contentEquals(className);
+        return classSymbol != null
+                && classSymbol.getQualifiedName().contentEquals(className);
       }
 
       @Override
@@ -50,12 +51,14 @@
     return new FieldReferenceMatcher() {
       @Override
       boolean classIsAppropriate(ClassSymbol classSymbol) {
-        return classSymbol.getQualifiedName().contentEquals(className);
+        return classSymbol != null
+                && classSymbol.getQualifiedName().contentEquals(className);
       }
 
       @Override
       boolean fieldSymbolIsAppropriate(Symbol symbol) {
-        return symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
+        return symbol != null
+                && symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
       }
     };
   }
@@ -64,12 +67,14 @@
     return new FieldReferenceMatcher() {
       @Override
       boolean classIsAppropriate(ClassSymbol classSymbol) {
-        return classSymbol.getQualifiedName().contentEquals(className);
+        return classSymbol != null
+                && classSymbol.getQualifiedName().contentEquals(className);
       }
 
       @Override
       boolean fieldSymbolIsAppropriate(Symbol symbol) {
-        return !symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
+        return symbol != null
+                && !symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
       }
     };
   }
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java
new file mode 100644
index 0000000..4625d43
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import com.google.errorprone.CompilationTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class CompatChangeCheckerTest {
+    private CompilationTestHelper compilationHelper;
+
+    @Before
+    public void setUp() {
+        compilationHelper = CompilationTestHelper.newInstance(
+                CompatChangeChecker.class, getClass());
+    }
+
+    @Test
+    public void testSimple() {
+        compilationHelper
+                .addSourceFile("/android/os/Build.java")
+                .addSourceLines("Example.java",
+                        "import android.os.Build;",
+                        "public class Example {",
+                        "  void test(int targetSdkVersion) {",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (targetSdkVersion < Build.VERSION_CODES.S) { }",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (targetSdkVersion <= Build.VERSION_CODES.S) { }",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (targetSdkVersion > Build.VERSION_CODES.S) { }",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (targetSdkVersion >= Build.VERSION_CODES.S) { }",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (targetSdkVersion == Build.VERSION_CODES.S) { }",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (targetSdkVersion != Build.VERSION_CODES.S) { }",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testObscure() {
+        compilationHelper
+                .addSourceFile("/android/os/Build.java")
+                .addSourceLines("Example.java",
+                        "import android.os.Build;",
+                        "import static android.os.Build.VERSION_CODES.S;",
+                        "public class Example {",
+                        "  void test(int targetSdkVersion) {",
+                        "    // BUG: Diagnostic contains:",
+                        "    boolean indirect = S >= targetSdkVersion;",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (targetSdkVersion > Build.VERSION_CODES.R) { }",
+                        "    if (targetSdkVersion >= Build.VERSION_CODES.R) { }",
+                        "    if (targetSdkVersion < Build.VERSION_CODES.R) { }",
+                        "    if (targetSdkVersion <= Build.VERSION_CODES.R) { }",
+                        "    // BUG: Diagnostic contains:",
+                        "    if (Build.VERSION_CODES.R < targetSdkVersion) { }",
+                        "    if (Build.VERSION_CODES.R <= targetSdkVersion) { }",
+                        "    if (Build.VERSION_CODES.R > targetSdkVersion) { }",
+                        "    if (Build.VERSION_CODES.R >= targetSdkVersion) { }",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testIgnored() {
+        compilationHelper
+                .addSourceFile("/android/os/Build.java")
+                .addSourceLines("Example.java",
+                        "import android.os.Build;",
+                        "public class Example {",
+                        "  void test(int targetSdkVersion) {",
+                        "    if (targetSdkVersion < Build.VERSION_CODES.DONUT) { }",
+                        "    String result = \"test\" + Build.VERSION_CODES.S;",
+                        "    if (targetSdkVersion != Build.VERSION_CODES.CUR_DEVELOPMENT) { }",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+}
diff --git a/errorprone/tests/res/android/os/Build.java b/errorprone/tests/res/android/os/Build.java
index bbf7ef2..2d354e2 100644
--- a/errorprone/tests/res/android/os/Build.java
+++ b/errorprone/tests/res/android/os/Build.java
@@ -18,6 +18,9 @@
 
 public class Build {
     public static class VERSION_CODES {
+        public static final int CUR_DEVELOPMENT = 10000;
         public static final int DONUT = 4;
+        public static final int R = 30;
+        public static final int S = CUR_DEVELOPMENT;
     }
 }
diff --git a/media/java/android/media/tv/TvChannelInfo.java b/media/java/android/media/tv/TvChannelInfo.java
index 635b130..11cb1f7 100644
--- a/media/java/android/media/tv/TvChannelInfo.java
+++ b/media/java/android/media/tv/TvChannelInfo.java
@@ -22,19 +22,44 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
 
 /**
+ * This class is used to specify information of a TV channel.
  * @hide
  */
 public final class TvChannelInfo implements Parcelable {
     static final String TAG = "TvChannelInfo";
+
+    /**
+     * App tag for {@link #getAppTag()}: the corresponding application of the channel is the same as
+     * the caller.
+     * <p>{@link #getAppType()} returns {@link #APP_TYPE_SELF} if and only if the app tag is
+     * {@link #APP_TAG_SELF}.
+     */
     public static final int APP_TAG_SELF = 0;
+    /**
+     * App tag for {@link #getAppType()}: the corresponding application of the channel is the same
+     * as the caller.
+     * <p>{@link #getAppType()} returns {@link #APP_TYPE_SELF} if and only if the app tag is
+     * {@link #APP_TAG_SELF}.
+     */
     public static final int APP_TYPE_SELF = 1;
+    /**
+     * App tag for {@link #getAppType()}: the corresponding app of the channel is a system
+     * application.
+     */
     public static final int APP_TYPE_SYSTEM = 2;
+    /**
+     * App tag for {@link #getAppType()}: the corresponding app of the channel is not a system
+     * application.
+     */
     public static final int APP_TYPE_NON_SYSTEM = 3;
 
     /** @hide */
@@ -68,6 +93,7 @@
     @AppType private final int mAppType;
     private final int mAppTag;
 
+    /** @hide */
     public TvChannelInfo(
             String inputId, @Nullable Uri channelUri, boolean isRecordingSession,
             boolean isForeground, @AppType int appType, int appTag) {
@@ -90,24 +116,41 @@
         mAppTag = source.readInt();
     }
 
+    /**
+     * Returns the TV input ID of the channel.
+     */
+    @NonNull
     public String getInputId() {
         return mInputId;
     }
 
+    /**
+     * Returns the channel URI of the channel.
+     * <p>Returns {@code null} if it's a passthrough input or the permission is not granted.
+     */
+    @Nullable
     public Uri getChannelUri() {
         return mChannelUri;
     }
 
+    /**
+     * Returns {@code true} if the channel session is a recording session.
+     * @see TvInputService.RecordingSession
+     */
     public boolean isRecordingSession() {
         return mIsRecordingSession;
     }
 
+    /**
+     * Returns {@code true} if the application is a foreground application.
+     * @see android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+     */
     public boolean isForeground() {
         return mIsForeground;
     }
 
     /**
-     * Gets app tag.
+     * Returns the app tag.
      * <p>App tag is used to differentiate one app from another.
      * {@link #APP_TAG_SELF} is for current app.
      */
@@ -115,6 +158,9 @@
         return mAppTag;
     }
 
+    /**
+     * Returns the app type.
+     */
     @AppType
     public int getAppType() {
         return mAppType;
@@ -126,7 +172,7 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mInputId);
         String uriString = mChannelUri == null ? null : mChannelUri.toString();
         dest.writeString(uriString);
@@ -145,4 +191,26 @@
                 + ";appType=" + mAppType
                 + ";appTag=" + mAppTag;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof TvChannelInfo)) {
+            return false;
+        }
+
+        TvChannelInfo other = (TvChannelInfo) o;
+
+        return TextUtils.equals(mInputId, other.getInputId())
+                && Objects.equals(mChannelUri, other.mChannelUri)
+                && mIsRecordingSession == other.mIsRecordingSession
+                && mIsForeground == other.mIsForeground
+                && mAppType == other.mAppType
+                && mAppTag == other.mAppTag;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mInputId, mChannelUri, mIsRecordingSession, mIsForeground, mAppType, mAppTag);
+    }
 }
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d38369f..c80f3c6 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -900,8 +900,13 @@
         public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
         }
 
-        /** @hide */
-        public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> tvChannelInfos) {
+        /**
+         * This is called when the information about current TV channels has been updated.
+         *
+         * @param tvChannelInfos a list of {@link TvChannelInfo} objects of new current channels.
+         * @hide
+         */
+        public void onCurrentTvChannelInfosUpdated(@NonNull List<TvChannelInfo> tvChannelInfos) {
         }
     }
 
@@ -1976,8 +1981,15 @@
     }
 
     /**
+     * Returns the list of TV channel information for {@link TvInputService.Session} that are
+     * currently in use.
+     * <p> Permission com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS is required to get
+     * the channel URIs. If the permission is not granted, {@link TvChannelInfo#getChannelUri()}
+     * returns {@code null}.
      * @hide
      */
+    @RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
+    @NonNull
     public List<TvChannelInfo> getCurrentTvChannelInfos() {
         try {
             return mService.getCurrentTvChannelInfos(mUserId);
diff --git a/non-updatable-api/Android.bp b/non-updatable-api/Android.bp
index 4037781..00b9019 100644
--- a/non-updatable-api/Android.bp
+++ b/non-updatable-api/Android.bp
@@ -23,13 +23,31 @@
 }
 
 filegroup {
+    name: "non-updatable-removed.txt",
+    srcs: ["removed.txt"],
+    visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
     name: "non-updatable-system-current.txt",
     srcs: ["system-current.txt"],
     visibility: ["//frameworks/base/api"],
 }
 
 filegroup {
+    name: "non-updatable-system-removed.txt",
+    srcs: ["system-removed.txt"],
+    visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
     name: "non-updatable-module-lib-current.txt",
     srcs: ["module-lib-current.txt"],
     visibility: ["//frameworks/base/api"],
 }
+
+filegroup {
+    name: "non-updatable-module-lib-removed.txt",
+    srcs: ["module-lib-removed.txt"],
+    visibility: ["//frameworks/base/api"],
+}
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index f116c80..2fad7f5 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -95,6 +95,7 @@
     field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
     field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
     field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
+    field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
     field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
     field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
     field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
@@ -125,6 +126,7 @@
     field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
     field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
     field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+    field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION";
     field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
@@ -1329,6 +1331,57 @@
 
 }
 
+package android.app.time {
+
+  public final class TimeManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void addTimeZoneDetectorListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public android.app.time.TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void removeTimeZoneDetectorListener(@NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public boolean updateTimeZoneConfiguration(@NonNull android.app.time.TimeZoneConfiguration);
+  }
+
+  @java.lang.FunctionalInterface public static interface TimeManager.TimeZoneDetectorListener {
+    method public void onChange();
+  }
+
+  public final class TimeZoneCapabilities implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getConfigureAutoDetectionEnabledCapability();
+    method public int getConfigureGeoDetectionEnabledCapability();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_NOT_ALLOWED = 20; // 0x14
+    field public static final int CAPABILITY_NOT_APPLICABLE = 30; // 0x1e
+    field public static final int CAPABILITY_NOT_SUPPORTED = 10; // 0xa
+    field public static final int CAPABILITY_POSSESSED = 40; // 0x28
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilities> CREATOR;
+  }
+
+  public final class TimeZoneCapabilitiesAndConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.app.time.TimeZoneCapabilities getCapabilities();
+    method @NonNull public android.app.time.TimeZoneConfiguration getConfiguration();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilitiesAndConfig> CREATOR;
+  }
+
+  public final class TimeZoneConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isAutoDetectionEnabled();
+    method public boolean isGeoDetectionEnabled();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneConfiguration> CREATOR;
+  }
+
+  public static final class TimeZoneConfiguration.Builder {
+    ctor public TimeZoneConfiguration.Builder();
+    ctor public TimeZoneConfiguration.Builder(@NonNull android.app.time.TimeZoneConfiguration);
+    method @NonNull public android.app.time.TimeZoneConfiguration build();
+    method @NonNull public android.app.time.TimeZoneConfiguration.Builder setAutoDetectionEnabled(boolean);
+    method @NonNull public android.app.time.TimeZoneConfiguration.Builder setGeoDetectionEnabled(boolean);
+  }
+
+}
+
 package android.app.usage {
 
   public final class CacheQuotaHint implements android.os.Parcelable {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d2485cc..506b608 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -892,9 +892,6 @@
                 Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
                 GlobalSettingsProto.Location.SETTINGS_LINK_TO_PERMISSIONS_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
-                GlobalSettingsProto.Location.GLOBAL_KILL_SWITCH);
-        dumpSetting(s, p,
                 Settings.Global.GNSS_SATELLITE_BLACKLIST,
                 GlobalSettingsProto.Location.GNSS_SATELLITE_BLACKLIST);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3ccb1f4..710c016 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -328,10 +328,6 @@
         return SettingsState.getUserIdFromKey(key);
     }
 
-    public static String settingTypeToString(int type) {
-        return SettingsState.settingTypeToString(type);
-    }
-
     public static String keyToString(int key) {
         return SettingsState.keyToString(key);
     }
@@ -373,8 +369,7 @@
             }
 
             case Settings.CALL_METHOD_GET_SECURE: {
-                Setting setting = getSecureSetting(name, requestingUserId,
-                        /*enableOverride=*/ true);
+                Setting setting = getSecureSetting(name, requestingUserId);
                 return packageValueForCallResult(setting, isTrackingGeneration(args));
             }
 
@@ -581,7 +576,7 @@
     }
 
     private ArrayList<String> buildSettingsList(Cursor cursor) {
-        final ArrayList<String> lines = new ArrayList<String>();
+        final ArrayList<String> lines = new ArrayList<>();
         try {
             while (cursor != null && cursor.moveToNext()) {
                 lines.add(cursor.getString(1) + "=" + cursor.getString(2));
@@ -1381,10 +1376,6 @@
     }
 
     private Setting getSecureSetting(String name, int requestingUserId) {
-        return getSecureSetting(name, requestingUserId, /*enableOverride=*/ false);
-    }
-
-    private Setting getSecureSetting(String name, int requestingUserId, boolean enableOverride) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
         }
@@ -1414,14 +1405,6 @@
                 return getSsaidSettingLocked(callingPkg, owningUserId);
             }
         }
-        if (enableOverride) {
-            if (Secure.LOCATION_MODE.equals(name)) {
-                final Setting overridden = getLocationModeSetting(owningUserId);
-                if (overridden != null) {
-                    return overridden;
-                }
-            }
-        }
 
         // Not the SSAID; do a straight lookup
         synchronized (mLock) {
@@ -1511,35 +1494,6 @@
         return null;
     }
 
-    private Setting getLocationModeSetting(int owningUserId) {
-        synchronized (mLock) {
-            final Setting setting = getGlobalSetting(
-                    Global.LOCATION_GLOBAL_KILL_SWITCH);
-            if (!"1".equals(setting.getValue())) {
-                return null;
-            }
-            // Global kill-switch is enabled. Return an empty value.
-            final SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
-                    SETTINGS_TYPE_SECURE, owningUserId);
-            return settingsState.new Setting(
-                    Secure.LOCATION_MODE,
-                    "", // value
-                    "", // tag
-                    "", // default value
-                    "", // package name
-                    false, // from system
-                    "0" // id
-            ) {
-                @Override
-                public boolean update(String value, boolean setDefault, String packageName,
-                        String tag, boolean forceNonSystemPackage, boolean overrideableByRestore) {
-                    Slog.wtf(LOG_TAG, "update shouldn't be called on this instance.");
-                    return false;
-                }
-            };
-        }
-    }
-
     private boolean insertSecureSetting(String name, String value, String tag,
             boolean makeDefault, int requestingUserId, boolean forceNotify,
             boolean overrideableByRestore) {
@@ -1808,12 +1762,8 @@
 
     private boolean hasWriteSecureSettingsPermission() {
         // Write secure settings is a more protected permission. If caller has it we are good.
-        if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
-                == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-
-        return false;
+        return getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+                == PackageManager.PERMISSION_GRANTED;
     }
 
     private void validateSystemSettingValue(String name, String value) {
@@ -3174,12 +3124,6 @@
             if (isGlobalSettingsKey(key) || isConfigSettingsKey(key)) {
                 final long token = Binder.clearCallingIdentity();
                 try {
-                    if (Global.LOCATION_GLOBAL_KILL_SWITCH.equals(name)
-                            && isGlobalSettingsKey(key)) {
-                        // When the global kill switch is updated, send the
-                        // change notification for the location setting.
-                        notifyLocationChangeForRunningUsers();
-                    }
                     notifySettingChangeForRunningUsers(key, name);
                 } finally {
                     Binder.restoreCallingIdentity(token);
@@ -3257,26 +3201,6 @@
             }
         }
 
-        private void notifyLocationChangeForRunningUsers() {
-            final List<UserInfo> users = mUserManager.getAliveUsers();
-
-            for (int i = 0; i < users.size(); i++) {
-                final int userId = users.get(i).id;
-
-                if (!mUserManager.isUserRunning(UserHandle.of(userId))) {
-                    continue;
-                }
-
-                // Increment the generation first, so observers always see the new value
-                final int key = makeKey(SETTINGS_TYPE_SECURE, userId);
-                mGenerationRegistry.incrementGeneration(key);
-
-                final Uri uri = getNotificationUriFor(key, Secure.LOCATION_MODE);
-                mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
-                        userId, 0, uri).sendToTarget();
-            }
-        }
-
         private boolean isConfigSettingsKey(int key) {
             return getTypeFromKey(key) == SETTINGS_TYPE_CONFIG;
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 6678cf6..b061df1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -34,7 +34,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.providers.settings.SettingsOperationProto;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -47,7 +46,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
 
 import libcore.io.IoUtils;
@@ -817,13 +815,6 @@
                 for (int i = 0; i < settingCount; i++) {
                     Setting setting = settings.valueAt(i);
 
-                    if (setting.isTransient()) {
-                        if (DEBUG_PERSISTENCE) {
-                            Slog.i(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName());
-                        }
-                        continue;
-                    }
-
                     writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
                             setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
                             setting.getTag(), setting.isDefaultFromSystem(),
@@ -1109,8 +1100,7 @@
                         ATTR_DEFAULT_VALUE_BASE64);
                 String isPreservedInRestoreString = parser.getAttributeValue(null,
                         ATTR_PRESERVE_IN_RESTORE);
-                boolean isPreservedInRestore = isPreservedInRestoreString != null
-                        && Boolean.parseBoolean(isPreservedInRestoreString);
+                boolean isPreservedInRestore = Boolean.parseBoolean(isPreservedInRestoreString);
                 String tag = null;
                 boolean fromSystem = false;
                 if (defaultValue != null) {
@@ -1308,14 +1298,6 @@
                     /* resetToDefault */ true);
         }
 
-        public boolean isTransient() {
-            switch (getTypeFromKey(getKey())) {
-                case SETTINGS_TYPE_GLOBAL:
-                    return ArrayUtils.contains(Global.TRANSIENT_SETTINGS, getName());
-            }
-            return false;
-        }
-
         public boolean update(String value, boolean setDefault, String packageName, String tag,
                 boolean forceNonSystemPackage, boolean overrideableByRestore) {
             return update(value, setDefault, packageName, tag, forceNonSystemPackage,
@@ -1444,7 +1426,7 @@
     }
 
     private static String fromBytes(byte[] bytes) {
-        final StringBuffer sb = new StringBuffer(bytes.length / 2);
+        final StringBuilder sb = new StringBuilder(bytes.length / 2);
 
         final int last = bytes.length - 1;
 
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 649ce392..cb03d40 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1012,18 +1012,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1087,8 +1081,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 88e497e..8e5849e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1012,18 +1012,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1087,8 +1081,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 649ce392..cb03d40 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1012,18 +1012,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1087,8 +1081,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 649ce392..cb03d40 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1012,18 +1012,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Zoom in"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Zoom out"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Move up"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string>
@@ -1087,8 +1081,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index f091e0b..e107ed5 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1012,18 +1012,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎Settings‎‏‎‎‏‎"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎Magnification Window‎‏‎‎‏‎"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎Magnification Window Controls‎‏‎‎‏‎"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎Zoom in‎‏‎‎‏‎"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎Zoom out‎‏‎‎‏‎"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‎‎Move up‎‏‎‎‏‎"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎Move down‎‏‎‎‏‎"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎Move left‎‏‎‎‏‎"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎Move right‎‏‎‎‏‎"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎Device controls‎‏‎‎‏‎"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎Add controls for your connected devices‎‏‎‎‏‎"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‏‏‎‎Set up device controls‎‏‎‎‏‎"</string>
@@ -1087,8 +1081,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ (disconnected)‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎Couldn\'t connect. Try again.‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎Pair new device‎‏‎‎‏‎"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎Build number‎‏‎‎‏‎"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎Build number copied to clipboard.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 524ced3..6fb84dd8 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1022,18 +1022,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nustatymai"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Didinimo langas"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Didinimo lango valdikliai"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Artinti"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Tolinti"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Perkelti aukštyn"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Perkelti žemyn"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Perkelti kairėn"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Perkelti dešinėn"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Įrenginio valdikliai"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridėkite prijungtų įrenginių valdiklių"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"Įrenginio valdiklių nustatymas"</string>
@@ -1099,8 +1093,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"„<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ (atjungta)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepavyko prijungti. Bandykite dar kartą."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 46cf45a..b76ebda 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1012,18 +1012,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configurações"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Aumentar zoom"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Diminuir zoom"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Mover para cima"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string>
@@ -1087,8 +1081,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 46cf45a..b76ebda 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1012,18 +1012,12 @@
     <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configurações"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
-    <!-- no translation found for accessibility_control_zoom_in (1189272315480097417) -->
-    <skip />
-    <!-- no translation found for accessibility_control_zoom_out (69578832020304084) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_up (6622825494014720136) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_down (5390922476900974512) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_left (8156206978511401995) -->
-    <skip />
-    <!-- no translation found for accessibility_control_move_right (8926821093629582888) -->
-    <skip />
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Aumentar zoom"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Diminuir zoom"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Mover para cima"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
     <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>
     <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string>
@@ -1087,8 +1081,6 @@
     <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
-    <!-- no translation found for build_number_clip_data_label (3623176728412560914) -->
-    <skip />
-    <!-- no translation found for build_number_copy_toast (877720921605503046) -->
-    <skip />
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index ee05c6c..a98f666 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -34,7 +34,6 @@
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
-import android.app.IAssistDataReceiver;
 import android.app.WindowConfiguration;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -43,7 +42,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -228,21 +226,10 @@
     /**
      * Starts the recents activity. The caller should manage the thread on which this is called.
      */
-    public void startRecentsActivity(Intent intent, final AssistDataReceiver assistDataReceiver,
+    public void startRecentsActivity(Intent intent, long eventTime,
             final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
         try {
-            IAssistDataReceiver receiver = null;
-            if (assistDataReceiver != null) {
-                receiver = new IAssistDataReceiver.Stub() {
-                    public void onHandleAssistData(Bundle resultData) {
-                        assistDataReceiver.onHandleAssistData(resultData);
-                    }
-                    public void onHandleAssistScreenshot(Bitmap screenshot) {
-                        assistDataReceiver.onHandleAssistScreenshot(screenshot);
-                    }
-                };
-            }
             IRecentsAnimationRunner runner = null;
             if (animationHandler != null) {
                 runner = new IRecentsAnimationRunner.Stub() {
@@ -272,7 +259,7 @@
                     }
                 };
             }
-            ActivityTaskManager.getService().startRecentsActivity(intent, receiver, runner);
+            ActivityTaskManager.getService().startRecentsActivity(intent, eventTime, runner);
             if (resultCallback != null) {
                 resultCallbackHandler.post(new Runnable() {
                     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 911bf9e..a705ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -37,6 +37,7 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.statusbar.CommandQueue;
 
 import javax.inject.Inject;
@@ -66,7 +67,8 @@
 
     @Inject
     public WindowMagnification(Context context, @Main Handler mainHandler,
-            CommandQueue commandQueue, ModeSwitchesController modeSwitchesController) {
+            CommandQueue commandQueue, ModeSwitchesController modeSwitchesController,
+            NavigationModeController navigationModeController) {
         super(context);
         mHandler = mainHandler;
         mLastConfiguration = new Configuration(context.getResources().getConfiguration());
@@ -77,6 +79,9 @@
         final WindowMagnificationController controller = new WindowMagnificationController(mContext,
                 mHandler, new SfVsyncFrameCallbackProvider(), null,
                 new SurfaceControl.Transaction(), this);
+        final int navBarMode = navigationModeController.addListener(
+                controller::onNavigationModeChanged);
+        controller.onNavigationModeChanged(navBarMode);
         mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
                 mContext, controller);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 3832ff30..c3474bb 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -17,6 +17,8 @@
 package com.android.systemui.accessibility;
 
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -117,6 +119,9 @@
     // The boundary of magnification frame.
     private final Rect mMagnificationFrameBoundary = new Rect();
 
+    private int mNavBarMode;
+    private int mNavGestureHeight;
+
     private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
     private Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback;
     private Locale mLocale;
@@ -195,6 +200,19 @@
                 R.dimen.magnification_drag_view_size);
         mOuterBorderSize = mResources.getDimensionPixelSize(
                 R.dimen.magnification_outer_border_margin);
+        updateNavigationBarDimensions();
+    }
+
+    private void updateNavigationBarDimensions() {
+        if (!supportsSwipeUpGesture()) {
+            mNavGestureHeight = 0;
+            return;
+        }
+        mNavGestureHeight = (mDisplaySize.x > mDisplaySize.y)
+                ? mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.navigation_bar_height_landscape)
+                : mResources.getDimensionPixelSize(
+                        com.android.internal.R.dimen.navigation_bar_gesture_height);
     }
 
     /**
@@ -239,6 +257,13 @@
         }
     }
 
+    /** Handles MirrorWindow position when the navigation bar mode changed. */
+    public void onNavigationModeChanged(int mode) {
+        mNavBarMode = mode;
+        updateNavigationBarDimensions();
+        updateMirrorViewLayout();
+    }
+
     /** Handles MirrorWindow position when the device rotation changed. */
     private void onRotate() {
         final Display display = mContext.getDisplay();
@@ -246,6 +271,7 @@
         display.getRealSize(mDisplaySize);
         setMagnificationFrameBoundary();
         mRotation = display.getRotation();
+        updateNavigationBarDimensions();
 
         if (!isWindowVisible()) {
             return;
@@ -401,15 +427,23 @@
      * moved close to the screen edges.
      */
     private void updateMirrorViewLayout() {
+        if (!isWindowVisible()) {
+            return;
+        }
+        final int maxMirrorViewX = mDisplaySize.x - mMirrorView.getWidth();
+        final int maxMirrorViewY = mDisplaySize.y - mMirrorView.getHeight() - mNavGestureHeight;
         WindowManager.LayoutParams params =
                 (WindowManager.LayoutParams) mMirrorView.getLayoutParams();
         params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
         params.y = mMagnificationFrame.top - mMirrorSurfaceMargin;
+        // If nav bar mode supports swipe-up gesture, the Y position of mirror view should not
+        // overlap nav bar window to prevent window-dragging obscured.
+        if (supportsSwipeUpGesture()) {
+            params.y = Math.min(params.y, maxMirrorViewY);
+        }
 
         // Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView
         // able to move close to the screen edges.
-        final int maxMirrorViewX = mDisplaySize.x - mMirrorView.getWidth();
-        final int maxMirrorViewY = mDisplaySize.y - mMirrorView.getHeight();
         final float translationX;
         final float translationY;
         if (params.x < 0) {
@@ -621,6 +655,10 @@
         return mMirrorView != null;
     }
 
+    private boolean supportsSwipeUpGesture() {
+        return mNavBarMode == NAV_BAR_MODE_2BUTTON || mNavBarMode == NAV_BAR_MODE_GESTURAL;
+    }
+
     private CharSequence formatStateDescription(float scale) {
         // Cache the locale-appropriate NumberFormat.  Configuration locale is guaranteed
         // non-null, so the first time this is called we will always get the appropriate
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
index fa33284..1e239b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
@@ -17,30 +17,44 @@
 package com.android.systemui.qs;
 
 import com.android.systemui.R;
+import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
 
-public class QSContainerImplController {
-    private final QSContainerImpl mView;
+class QSContainerImplController extends ViewController<QSContainerImpl> {
     private final QuickStatusBarHeaderController mQuickStatusBarHeaderController;
 
     private QSContainerImplController(QSContainerImpl view,
             QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) {
-        mView = view;
+        super(view);
         mQuickStatusBarHeaderController = quickStatusBarHeaderControllerBuilder
                 .setQuickStatusBarHeader(mView.findViewById(R.id.header)).build();
     }
 
+    @Override
+    public void init() {
+        super.init();
+        mQuickStatusBarHeaderController.init();
+    }
+
     public void setListening(boolean listening) {
         mQuickStatusBarHeaderController.setListening(listening);
     }
 
-    public static class Builder {
+    @Override
+    protected void onViewAttached() {
+    }
+
+    @Override
+    protected void onViewDetached() {
+    }
+
+    static class Builder {
         private final QuickStatusBarHeaderController.Builder mQuickStatusBarHeaderControllerBuilder;
         private QSContainerImpl mView;
 
         @Inject
-        public Builder(
+        Builder(
                 QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) {
             mQuickStatusBarHeaderControllerBuilder = quickStatusBarHeaderControllerBuilder;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index f1bb899..3a78365 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -142,7 +142,7 @@
         mQSContainerImplController = mQSContainerImplControllerBuilder
                 .setQSContainerImpl((QSContainerImpl) view)
                 .build();
-
+        mQSContainerImplController.init();
 
         mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter);
         mQSAnimator = new QSAnimator(this, mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
@@ -367,14 +367,13 @@
         if (DEBUG) Log.d(TAG, "setListening " + listening);
         mListening = listening;
         mQSContainerImplController.setListening(listening);
-        mHeader.setListening(listening);
         mFooter.setListening(listening);
         mQSPanel.setListening(mListening, mQsExpanded);
     }
 
     @Override
     public void setHeaderListening(boolean listening) {
-        mHeader.setListening(listening);
+        mQSContainerImplController.setListening(listening);
         mFooter.setListening(listening);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 544249a..a9fbc74 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -17,27 +17,16 @@
 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
 import android.annotation.ColorInt;
-import android.app.AlarmManager;
+import android.app.AlarmManager.AlarmClockInfo;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.media.AudioManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.AlarmClock;
-import android.provider.Settings;
-import android.service.notification.ZenModeConfig;
-import android.text.format.DateUtils;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.MathUtils;
 import android.util.Pair;
 import android.view.ContextThemeWrapper;
@@ -53,93 +42,48 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LifecycleRegistry;
 
-import com.android.internal.logging.UiEventLogger;
 import com.android.settingslib.Utils;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DualToneHandler;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.privacy.OngoingPrivacyChip;
-import com.android.systemui.privacy.PrivacyChipEvent;
-import com.android.systemui.privacy.PrivacyItem;
-import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.qs.QSDetail.Callback;
-import com.android.systemui.qs.carrier.QSCarrierGroup;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
-import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.policy.DateView;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.util.RingerModeTracker;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
 /**
  * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
  * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
  * contents.
  */
-public class QuickStatusBarHeader extends RelativeLayout implements
-        View.OnClickListener, NextAlarmController.NextAlarmChangeCallback,
-        ZenModeController.Callback, LifecycleOwner {
-    private static final String TAG = "QuickStatusBarHeader";
-    private static final boolean DEBUG = false;
+public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwner {
 
-    /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
-    private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
-    private static final int FADE_ANIMATION_DURATION_MS = 300;
-    private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
     public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
 
-    private final NextAlarmController mAlarmController;
-    private final ZenModeController mZenController;
-    private final StatusBarIconController mStatusBarIconController;
-    private final ActivityStarter mActivityStarter;
-
-    private QSPanel mQsPanel;
-
     private boolean mExpanded;
-    private boolean mListening;
     private boolean mQsDisabled;
 
-    private QSCarrierGroup mCarrierGroup;
     protected QuickQSPanel mHeaderQsPanel;
-    protected QSTileHost mHost;
-    private TintedIconManager mIconManager;
     private TouchAnimator mStatusIconsAlphaAnimator;
     private TouchAnimator mHeaderTextContainerAlphaAnimator;
     private TouchAnimator mPrivacyChipAlphaAnimator;
     private DualToneHandler mDualToneHandler;
-    private final CommandQueue mCommandQueue;
 
     private View mSystemIconsView;
     private View mQuickQsStatusIcons;
     private View mHeaderTextContainerView;
 
-    private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
-    private AlarmManager.AlarmClockInfo mNextAlarm;
-
     private ImageView mNextAlarmIcon;
     /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
     private TextView mNextAlarmTextView;
@@ -149,23 +93,13 @@
     private TextView mRingerModeTextView;
     private View mRingerContainer;
     private Clock mClockView;
-    private DateView mDateView;
     private OngoingPrivacyChip mPrivacyChip;
     private Space mSpace;
     private BatteryMeterView mBatteryRemainingIcon;
-    private RingerModeTracker mRingerModeTracker;
-    private DemoModeController mDemoModeController;
-    private DemoMode mDemoModeReceiver;
-    private UserTracker mUserTracker;
-    private boolean mAllIndicatorsEnabled;
-    private boolean mMicCameraIndicatorsEnabled;
 
-    private PrivacyItemController mPrivacyItemController;
-    private final UiEventLogger mUiEventLogger;
     // Used for RingerModeTracker
     private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
 
-    private boolean mHasTopCutout = false;
     private int mStatusBarPaddingTop = 0;
     private int mRoundedCornerPadding = 0;
     private int mContentMarginStart;
@@ -175,59 +109,11 @@
     private int mCutOutPaddingRight;
     private float mExpandedHeaderAlpha = 1.0f;
     private float mKeyguardExpansionFraction;
-    private boolean mPrivacyChipLogged = false;
 
-    private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
-        @Override
-        public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) {
-            mPrivacyChip.setPrivacyList(privacyItems);
-            setChipVisibility(!privacyItems.isEmpty());
-        }
-
-        @Override
-        public void onFlagAllChanged(boolean flag) {
-            if (mAllIndicatorsEnabled != flag) {
-                mAllIndicatorsEnabled = flag;
-                update();
-            }
-        }
-
-        @Override
-        public void onFlagMicCameraChanged(boolean flag) {
-            if (mMicCameraIndicatorsEnabled != flag) {
-                mMicCameraIndicatorsEnabled = flag;
-                update();
-            }
-        }
-
-        private void update() {
-            StatusIconContainer iconContainer = requireViewById(R.id.statusIcons);
-            iconContainer.setIgnoredSlots(getIgnoredIconSlots());
-            setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
-        }
-    };
-
-    @Inject
-    public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
-            NextAlarmController nextAlarmController, ZenModeController zenModeController,
-            StatusBarIconController statusBarIconController,
-            ActivityStarter activityStarter, PrivacyItemController privacyItemController,
-            CommandQueue commandQueue, RingerModeTracker ringerModeTracker,
-            UiEventLogger uiEventLogger, DemoModeController demoModeController,
-            UserTracker userTracker) {
+    public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mAlarmController = nextAlarmController;
-        mZenController = zenModeController;
-        mStatusBarIconController = statusBarIconController;
-        mActivityStarter = activityStarter;
-        mPrivacyItemController = privacyItemController;
         mDualToneHandler = new DualToneHandler(
                 new ContextThemeWrapper(context, R.style.QSHeaderTheme));
-        mCommandQueue = commandQueue;
-        mRingerModeTracker = ringerModeTracker;
-        mUiEventLogger = uiEventLogger;
-        mDemoModeController = demoModeController;
-        mUserTracker = userTracker;
     }
 
     @Override
@@ -237,11 +123,6 @@
         mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
         mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
         mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
-        StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
-        // Ignore privacy icons because they show in the space above QQS
-        iconContainer.addIgnoredSlots(getIgnoredIconSlots());
-        iconContainer.setShouldRestrictIcons(false);
-        mIconManager = new TintedIconManager(iconContainer, mCommandQueue);
 
         // Views corresponding to the header info section (e.g. ringer and next alarm).
         mHeaderTextContainerView = findViewById(R.id.header_text_container);
@@ -249,36 +130,18 @@
         mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
         mNextAlarmTextView = findViewById(R.id.next_alarm_text);
         mNextAlarmContainer = findViewById(R.id.alarm_container);
-        mNextAlarmContainer.setOnClickListener(this::onClick);
         mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
         mRingerModeTextView = findViewById(R.id.ringer_mode_text);
         mRingerContainer = findViewById(R.id.ringer_container);
-        mRingerContainer.setOnClickListener(this::onClick);
         mPrivacyChip = findViewById(R.id.privacy_chip);
-        mPrivacyChip.setOnClickListener(this::onClick);
-        mCarrierGroup = findViewById(R.id.carrier_group);
-
 
         updateResources();
 
         Rect tintArea = new Rect(0, 0, 0, 0);
-        int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
-                android.R.attr.colorForeground);
-        float intensity = getColorIntensity(colorForeground);
-        int fillColor = mDualToneHandler.getSingleColor(intensity);
-
         // Set light text on the header icons because they will always be on a black background
         applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
 
-        // Set the correct tint for the status icons so they contrast
-        mIconManager.setTint(fillColor);
-        mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
-        mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
-
         mClockView = findViewById(R.id.clock);
-        mClockView.setOnClickListener(this);
-        mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
-        mDateView = findViewById(R.id.date);
         mSpace = findViewById(R.id.space);
 
         // Tint for the battery icons are handled in setupHost()
@@ -290,33 +153,28 @@
         mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
         mRingerModeTextView.setSelected(true);
         mNextAlarmTextView.setSelected(true);
+    }
 
-        mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
-        mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
+    void onAttach(TintedIconManager iconManager) {
+        int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
+                android.R.attr.colorForeground);
+        float intensity = getColorIntensity(colorForeground);
+        int fillColor = mDualToneHandler.getSingleColor(intensity);
+
+        // Set the correct tint for the status icons so they contrast
+        iconManager.setTint(fillColor);
+        mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
+        mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
     }
 
     public QuickQSPanel getHeaderQsPanel() {
         return mHeaderQsPanel;
     }
 
-    private List<String> getIgnoredIconSlots() {
-        ArrayList<String> ignored = new ArrayList<>();
-        if (getChipEnabled()) {
-            ignored.add(mContext.getResources().getString(
-                    com.android.internal.R.string.status_bar_camera));
-            ignored.add(mContext.getResources().getString(
-                    com.android.internal.R.string.status_bar_microphone));
-            if (mAllIndicatorsEnabled) {
-                ignored.add(mContext.getResources().getString(
-                        com.android.internal.R.string.status_bar_location));
-            }
-        }
-
-        return ignored;
-    }
-
-    private void updateStatusText() {
-        boolean changed = updateRingerStatus() || updateAlarmStatus();
+    void updateStatusText(int ringerMode, AlarmClockInfo nextAlarm, boolean zenOverridingRinger,
+            boolean use24HourFormat) {
+        boolean changed = updateRingerStatus(ringerMode, zenOverridingRinger)
+                || updateAlarmStatus(nextAlarm, use24HourFormat);
 
         if (changed) {
             boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
@@ -326,32 +184,17 @@
         }
     }
 
-    private void setChipVisibility(boolean chipVisible) {
-        if (chipVisible && getChipEnabled()) {
-            mPrivacyChip.setVisibility(View.VISIBLE);
-            // Makes sure that the chip is logged as viewed at most once each time QS is opened
-            // mListening makes sure that the callback didn't return after the user closed QS
-            if (!mPrivacyChipLogged && mListening) {
-                mPrivacyChipLogged = true;
-                mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW);
-            }
-        } else {
-            mPrivacyChip.setVisibility(View.GONE);
-        }
-    }
-
-    private boolean updateRingerStatus() {
+    private boolean updateRingerStatus(int ringerMode, boolean zenOverridingRinger) {
         boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
         CharSequence originalRingerText = mRingerModeTextView.getText();
 
         boolean ringerVisible = false;
-        if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
-                mZenController.getConsolidatedPolicy())) {
-            if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
+        if (!zenOverridingRinger) {
+            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
                 mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
                 mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
                 ringerVisible = true;
-            } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
+            } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
                 mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
                 mRingerModeTextView.setText(R.string.qs_status_phone_muted);
                 ringerVisible = true;
@@ -365,14 +208,14 @@
                 !Objects.equals(originalRingerText, mRingerModeTextView.getText());
     }
 
-    private boolean updateAlarmStatus() {
+    private boolean updateAlarmStatus(AlarmClockInfo nextAlarm, boolean use24HourFormat) {
         boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
         CharSequence originalAlarmText = mNextAlarmTextView.getText();
 
         boolean alarmVisible = false;
-        if (mNextAlarm != null) {
+        if (nextAlarm != null) {
             alarmVisible = true;
-            mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
+            mNextAlarmTextView.setText(formatNextAlarm(nextAlarm, use24HourFormat));
         }
         mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
         mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
@@ -419,7 +262,7 @@
         setMinimumHeight(sbHeight + qqsHeight);
     }
 
-    private void updateResources() {
+    void updateResources() {
         Resources resources = mContext.getResources();
         updateMinimumHeight();
 
@@ -529,18 +372,6 @@
     }
 
     @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mRingerModeTracker.getRingerModeInternal().observe(this, ringer -> {
-            mRingerMode = ringer;
-            updateStatusText();
-        });
-        mStatusBarIconController.addIconGroup(mIconManager);
-        mDemoModeController.addCallback(mDemoModeReceiver);
-        requestApplyInsets();
-    }
-
-    @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         // Handle padding of the clock
         DisplayCutout cutout = insets.getDisplayCutout();
@@ -563,17 +394,14 @@
         if (cutout != null) {
             Rect topCutout = cutout.getBoundingRectTop();
             if (topCutout.isEmpty() || cornerCutout) {
-                mHasTopCutout = false;
                 lp.width = 0;
                 mSpace.setVisibility(View.GONE);
             } else {
-                mHasTopCutout = true;
                 lp.width = topCutout.width();
                 mSpace.setVisibility(View.VISIBLE);
             }
         }
         mSpace.setLayoutParams(lp);
-        setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
         mCutOutPaddingLeft = padding.first;
         mCutOutPaddingRight = padding.second;
         mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
@@ -611,103 +439,14 @@
                 0);
     }
 
-    @Override
-    @VisibleForTesting
-    public void onDetachedFromWindow() {
-        setListening(false);
-        mRingerModeTracker.getRingerModeInternal().removeObservers(this);
-        mStatusBarIconController.removeIconGroup(mIconManager);
-        mDemoModeController.removeCallback(mDemoModeReceiver);
-        super.onDetachedFromWindow();
-    }
-
-    public void setListening(boolean listening) {
-        if (listening == mListening) {
-            return;
-        }
-        mHeaderQsPanel.setListening(listening);
-        if (mHeaderQsPanel.switchTileLayout()) {
-            updateResources();
-        }
-        mListening = listening;
-
-        if (listening) {
-            mZenController.addCallback(this);
-            mAlarmController.addCallback(this);
-            mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
-            // Get the most up to date info
-            mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
-            mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
-            mPrivacyItemController.addCallback(mPICCallback);
-        } else {
-            mZenController.removeCallback(this);
-            mAlarmController.removeCallback(this);
-            mLifecycle.setCurrentState(Lifecycle.State.CREATED);
-            mPrivacyItemController.removeCallback(mPICCallback);
-            mPrivacyChipLogged = false;
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v == mClockView) {
-            mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
-                    AlarmClock.ACTION_SHOW_ALARMS), 0);
-        } else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) {
-            if (mNextAlarm.getShowIntent() != null) {
-                mActivityStarter.postStartActivityDismissingKeyguard(
-                        mNextAlarm.getShowIntent());
-            } else {
-                Log.d(TAG, "No PendingIntent for next alarm. Using default intent");
-                mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
-                        AlarmClock.ACTION_SHOW_ALARMS), 0);
-            }
-        } else if (v == mPrivacyChip) {
-            // If the privacy chip is visible, it means there were some indicators
-            Handler mUiHandler = new Handler(Looper.getMainLooper());
-            mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK);
-            mUiHandler.post(() -> {
-                mActivityStarter.postStartActivityDismissingKeyguard(
-                        new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
-                mHost.collapsePanels();
-            });
-        } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) {
-            mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
-                    Settings.ACTION_SOUND_SETTINGS), 0);
-        }
-    }
-
-    @Override
-    public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
-        mNextAlarm = nextAlarm;
-        updateStatusText();
-    }
-
-    @Override
-    public void onZenChanged(int zen) {
-        updateStatusText();
-    }
-
-    @Override
-    public void onConfigChanged(ZenModeConfig config) {
-        updateStatusText();
-    }
-
     public void updateEverything() {
         post(() -> setClickable(!mExpanded));
     }
 
     public void setQSPanel(final QSPanel qsPanel) {
-        mQsPanel = qsPanel;
-        setupHost(qsPanel.getHost());
-    }
-
-    public void setupHost(final QSTileHost host) {
-        mHost = host;
         //host.setHeaderView(mExpandIndicator);
-        mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
-        mHeaderQsPanel.setHost(host, null /* No customization in header */);
-
+        mHeaderQsPanel.setQSPanelAndHeader(qsPanel, this);
+        mHeaderQsPanel.setHost(qsPanel.getHost(), null /* No customization in header */);
 
         Rect tintArea = new Rect(0, 0, 0, 0);
         int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
@@ -721,12 +460,11 @@
         mHeaderQsPanel.setCallback(qsPanelCallback);
     }
 
-    private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
+    private String formatNextAlarm(AlarmClockInfo info, boolean use24HourFormat) {
         if (info == null) {
             return "";
         }
-        String skeleton = android.text.format.DateFormat
-                .is24HourFormat(mContext, mUserTracker.getUserId()) ? "EHm" : "Ehma";
+        String skeleton = use24HourFormat ? "EHm" : "Ehma";
         String pattern = android.text.format.DateFormat
                 .getBestDateTimePattern(Locale.getDefault(), skeleton);
         return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
@@ -777,37 +515,4 @@
             updateHeaderTextContainerAlphaAnimator();
         }
     }
-
-    private boolean getChipEnabled() {
-        return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
-    }
-
-    private static class ClockDemoModeReceiver implements DemoMode {
-        private Clock mClockView;
-
-        @Override
-        public List<String> demoCommands() {
-            return List.of(COMMAND_CLOCK);
-        }
-
-        ClockDemoModeReceiver(Clock clockView) {
-            mClockView = clockView;
-        }
-
-        @Override
-        public void dispatchDemoCommand(String command, Bundle args) {
-            mClockView.dispatchDemoCommand(command, args);
-        }
-
-        @Override
-        public void onDemoModeStarted() {
-            mClockView.onDemoModeStarted();
-        }
-
-        @Override
-        public void onDemoModeFinished() {
-            mClockView.onDemoModeFinished();
-        }
-    }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index d899acb..676a300 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -16,36 +16,393 @@
 
 package com.android.systemui.qs;
 
+import android.app.AlarmManager.AlarmClockInfo;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.AlarmClock;
+import android.provider.Settings;
+import android.service.notification.ZenModeConfig;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.privacy.OngoingPrivacyChip;
+import com.android.systemui.privacy.PrivacyChipEvent;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.qs.carrier.QSCarrierGroupController;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusIconContainer;
+import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeController.Callback;
+import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.ViewController;
+
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.inject.Inject;
 
-public class QuickStatusBarHeaderController {
-    private final QuickStatusBarHeader mView;
+/**
+ * Controller for {@link QuickStatusBarHeader}.
+ */
+class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader> {
+    private static final String TAG = "QuickStatusBarHeader";
+
+    private final ZenModeController mZenModeController;
+    private final NextAlarmController mNextAlarmController;
+    private final PrivacyItemController mPrivacyItemController;
+    private final RingerModeTracker mRingerModeTracker;
+    private final ActivityStarter mActivityStarter;
+    private final UiEventLogger mUiEventLogger;
     private final QSCarrierGroupController mQSCarrierGroupController;
+    private final QuickQSPanel mHeaderQsPanel;
+    private final LifecycleRegistry mLifecycle;
+    private final OngoingPrivacyChip mPrivacyChip;
+    private final Clock mClockView;
+    private final View mNextAlarmContainer;
+    private final View mRingerContainer;
+    private final QSTileHost mQSTileHost;
+    private final StatusBarIconController mStatusBarIconController;
+    private final CommandQueue mCommandQueue;
+    private final DemoModeController mDemoModeController;
+    private final UserTracker mUserTracker;
+    private final StatusIconContainer mIconContainer;
+    private final StatusBarIconController.TintedIconManager mIconManager;
+    private final DemoMode mDemoModeReceiver;
+
+    private boolean mListening;
+    private AlarmClockInfo mNextAlarm;
+    private boolean mAllIndicatorsEnabled;
+    private boolean mMicCameraIndicatorsEnabled;
+    private boolean mPrivacyChipLogged;
+    private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
+
+    private final ZenModeController.Callback mZenModeControllerCallback = new Callback() {
+        @Override
+        public void onZenChanged(int zen) {
+            mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+                    use24HourFormat());
+        }
+
+        @Override
+        public void onConfigChanged(ZenModeConfig config) {
+            mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+                    use24HourFormat());
+        }
+    };
+
+    private boolean use24HourFormat() {
+        return android.text.format.DateFormat.is24HourFormat(
+                mView.getContext(), mUserTracker.getUserId());
+
+    }
+
+    private final NextAlarmChangeCallback mNextAlarmChangeCallback = new NextAlarmChangeCallback() {
+        @Override
+        public void onNextAlarmChanged(AlarmClockInfo nextAlarm) {
+            mNextAlarm = nextAlarm;
+            mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+                    use24HourFormat());
+        }
+    };
+
+    private final LifecycleOwner mLifecycleOwner = new LifecycleOwner() {
+        @NonNull
+        @Override
+        public Lifecycle getLifecycle() {
+            return mLifecycle;
+        }
+    };
+
+    private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
+        @Override
+        public void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) {
+            mPrivacyChip.setPrivacyList(privacyItems);
+            setChipVisibility(!privacyItems.isEmpty());
+        }
+
+        @Override
+        public void onFlagAllChanged(boolean flag) {
+            if (mAllIndicatorsEnabled != flag) {
+                mAllIndicatorsEnabled = flag;
+                update();
+            }
+        }
+
+        @Override
+        public void onFlagMicCameraChanged(boolean flag) {
+            if (mMicCameraIndicatorsEnabled != flag) {
+                mMicCameraIndicatorsEnabled = flag;
+                update();
+            }
+        }
+
+        private void update() {
+            StatusIconContainer iconContainer = mView.requireViewById(R.id.statusIcons);
+            iconContainer.setIgnoredSlots(getIgnoredIconSlots());
+            setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
+        }
+    };
+
+    private View.OnClickListener mOnClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (v == mClockView) {
+                mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+                        AlarmClock.ACTION_SHOW_ALARMS), 0);
+            } else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) {
+                if (mNextAlarm.getShowIntent() != null) {
+                    mActivityStarter.postStartActivityDismissingKeyguard(
+                            mNextAlarm.getShowIntent());
+                } else {
+                    Log.d(TAG, "No PendingIntent for next alarm. Using default intent");
+                    mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+                            AlarmClock.ACTION_SHOW_ALARMS), 0);
+                }
+            } else if (v == mPrivacyChip) {
+                // If the privacy chip is visible, it means there were some indicators
+                Handler mUiHandler = new Handler(Looper.getMainLooper());
+                mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK);
+                mUiHandler.post(() -> {
+                    mActivityStarter.postStartActivityDismissingKeyguard(
+                            new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
+                    mQSTileHost.collapsePanels();
+                });
+            } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) {
+                mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+                        Settings.ACTION_SOUND_SETTINGS), 0);
+            }
+        }
+    };
 
     private QuickStatusBarHeaderController(QuickStatusBarHeader view,
+            ZenModeController zenModeController, NextAlarmController nextAlarmController,
+            PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker,
+            ActivityStarter activityStarter, UiEventLogger uiEventLogger,
+            QSTileHost qsTileHost, StatusBarIconController statusBarIconController,
+            CommandQueue commandQueue, DemoModeController demoModeController,
+            UserTracker userTracker,
             QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
-        mView = view;
+        super(view);
+        mZenModeController = zenModeController;
+        mNextAlarmController = nextAlarmController;
+        mPrivacyItemController = privacyItemController;
+        mRingerModeTracker = ringerModeTracker;
+        mActivityStarter = activityStarter;
+        mUiEventLogger = uiEventLogger;
+        mQSTileHost = qsTileHost;
+        mStatusBarIconController = statusBarIconController;
+        mCommandQueue = commandQueue;
+        mDemoModeController = demoModeController;
+        mUserTracker = userTracker;
+        mLifecycle = new LifecycleRegistry(mLifecycleOwner);
+
         mQSCarrierGroupController = qsCarrierGroupControllerBuilder
                 .setQSCarrierGroup(mView.findViewById(R.id.carrier_group))
                 .build();
+
+
+        mPrivacyChip = mView.findViewById(R.id.privacy_chip);
+        mHeaderQsPanel = mView.findViewById(R.id.quick_qs_panel);
+        mNextAlarmContainer = mView.findViewById(R.id.alarm_container);
+        mClockView = mView.findViewById(R.id.clock);
+        mRingerContainer = mView.findViewById(R.id.ringer_container);
+        mIconContainer = mView.findViewById(R.id.statusIcons);
+
+        mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, mCommandQueue);
+        mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
+    }
+
+    @Override
+    protected void onViewAttached() {
+        mRingerModeTracker.getRingerModeInternal().observe(mLifecycleOwner, ringer -> {
+            mRingerMode = ringer;
+            mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(),
+                    use24HourFormat());
+        });
+
+        mClockView.setOnClickListener(mOnClickListener);
+        mNextAlarmContainer.setOnClickListener(mOnClickListener);
+        mRingerContainer.setOnClickListener(mOnClickListener);
+        mPrivacyChip.setOnClickListener(mOnClickListener);
+
+        // Ignore privacy icons because they show in the space above QQS
+        mIconContainer.addIgnoredSlots(getIgnoredIconSlots());
+        mIconContainer.setShouldRestrictIcons(false);
+        mStatusBarIconController.addIconGroup(mIconManager);
+
+        mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+        mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
+
+        setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
+
+        mView.onAttach(mIconManager);
+
+        mDemoModeController.addCallback(mDemoModeReceiver);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        mRingerModeTracker.getRingerModeInternal().removeObservers(mLifecycleOwner);
+        mClockView.setOnClickListener(null);
+        mNextAlarmContainer.setOnClickListener(null);
+        mRingerContainer.setOnClickListener(null);
+        mPrivacyChip.setOnClickListener(null);
+        mStatusBarIconController.removeIconGroup(mIconManager);
+        mDemoModeController.removeCallback(mDemoModeReceiver);
+        setListening(false);
     }
 
     public void setListening(boolean listening) {
         mQSCarrierGroupController.setListening(listening);
-        // TODO: move mView.setListening logic into here.
-        mView.setListening(listening);
+
+        if (listening == mListening) {
+            return;
+        }
+        mListening = listening;
+
+        mHeaderQsPanel.setListening(listening);
+        if (mHeaderQsPanel.switchTileLayout()) {
+            mView.updateResources();
+        }
+
+        if (listening) {
+            mZenModeController.addCallback(mZenModeControllerCallback);
+            mNextAlarmController.addCallback(mNextAlarmChangeCallback);
+            mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
+            // Get the most up to date info
+            mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+            mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
+            mPrivacyItemController.addCallback(mPICCallback);
+        } else {
+            mZenModeController.removeCallback(mZenModeControllerCallback);
+            mNextAlarmController.removeCallback(mNextAlarmChangeCallback);
+            mLifecycle.setCurrentState(Lifecycle.State.CREATED);
+            mPrivacyItemController.removeCallback(mPICCallback);
+            mPrivacyChipLogged = false;
+        }
+    }
+
+    private void setChipVisibility(boolean chipVisible) {
+        if (chipVisible && getChipEnabled()) {
+            mPrivacyChip.setVisibility(View.VISIBLE);
+            // Makes sure that the chip is logged as viewed at most once each time QS is opened
+            // mListening makes sure that the callback didn't return after the user closed QS
+            if (!mPrivacyChipLogged && mListening) {
+                mPrivacyChipLogged = true;
+                mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW);
+            }
+        } else {
+            mPrivacyChip.setVisibility(View.GONE);
+        }
+    }
+
+    private List<String> getIgnoredIconSlots() {
+        ArrayList<String> ignored = new ArrayList<>();
+        if (getChipEnabled()) {
+            ignored.add(mView.getResources().getString(
+                    com.android.internal.R.string.status_bar_camera));
+            ignored.add(mView.getResources().getString(
+                    com.android.internal.R.string.status_bar_microphone));
+            if (mAllIndicatorsEnabled) {
+                ignored.add(mView.getResources().getString(
+                        com.android.internal.R.string.status_bar_location));
+            }
+        }
+
+        return ignored;
+    }
+
+    private boolean getChipEnabled() {
+        return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
+    }
+
+    private boolean isZenOverridingRinger() {
+        return ZenModeConfig.isZenOverridingRinger(mZenModeController.getZen(),
+                mZenModeController.getConsolidatedPolicy());
     }
 
 
-    public static class Builder {
+    private static class ClockDemoModeReceiver implements DemoMode {
+        private Clock mClockView;
+
+        @Override
+        public List<String> demoCommands() {
+            return List.of(COMMAND_CLOCK);
+        }
+
+        ClockDemoModeReceiver(Clock clockView) {
+            mClockView = clockView;
+        }
+
+        @Override
+        public void dispatchDemoCommand(String command, Bundle args) {
+            mClockView.dispatchDemoCommand(command, args);
+        }
+
+        @Override
+        public void onDemoModeStarted() {
+            mClockView.onDemoModeStarted();
+        }
+
+        @Override
+        public void onDemoModeFinished() {
+            mClockView.onDemoModeFinished();
+        }
+    }
+
+    static class Builder {
+        private final ZenModeController mZenModeController;
+        private final NextAlarmController mNextAlarmController;
+        private final PrivacyItemController mPrivacyItemController;
+        private final RingerModeTracker mRingerModeTracker;
+        private final ActivityStarter mActivityStarter;
+        private final UiEventLogger mUiEventLogger;
+        private final QSTileHost mQsTileHost;
+        private final StatusBarIconController mStatusBarIconController;
+        private final CommandQueue mCommandQueue;
+        private final DemoModeController mDemoModeController;
+        private final UserTracker mUserTracker;
         private final QSCarrierGroupController.Builder mQSCarrierGroupControllerBuilder;
         private QuickStatusBarHeader mView;
 
         @Inject
-        public Builder(QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
+        Builder(ZenModeController zenModeController, NextAlarmController nextAlarmController,
+                PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker,
+                ActivityStarter activityStarter, UiEventLogger uiEventLogger, QSTileHost qsTileHost,
+                StatusBarIconController statusBarIconController, CommandQueue commandQueue,
+                DemoModeController demoModeController, UserTracker userTracker,
+                QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) {
+            mZenModeController = zenModeController;
+            mNextAlarmController = nextAlarmController;
+            mPrivacyItemController = privacyItemController;
+            mRingerModeTracker = ringerModeTracker;
+            mActivityStarter = activityStarter;
+            mUiEventLogger = uiEventLogger;
+            mQsTileHost = qsTileHost;
+            mStatusBarIconController = statusBarIconController;
+            mCommandQueue = commandQueue;
+            mDemoModeController = demoModeController;
+            mUserTracker = userTracker;
             mQSCarrierGroupControllerBuilder = qsCarrierGroupControllerBuilder;
         }
 
@@ -54,8 +411,13 @@
             return this;
         }
 
-        public QuickStatusBarHeaderController build() {
-            return new QuickStatusBarHeaderController(mView, mQSCarrierGroupControllerBuilder);
+
+        QuickStatusBarHeaderController build() {
+            return new QuickStatusBarHeaderController(mView, mZenModeController,
+                    mNextAlarmController, mPrivacyItemController, mRingerModeTracker,
+                    mActivityStarter, mUiEventLogger, mQsTileHost, mStatusBarIconController,
+                    mCommandQueue, mDemoModeController, mUserTracker,
+                    mQSCarrierGroupControllerBuilder);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
index df03c3e..0aa9d4d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -48,6 +48,7 @@
     private long mTotalBytes;
     private MediaMuxer mMuxer;
     private boolean mMic;
+    private boolean mStarted;
 
     private int mTrackId = -1;
 
@@ -263,10 +264,14 @@
     * start recording
      * @throws IllegalStateException if recording fails to initialize
     */
-    public void start() throws IllegalStateException {
-        if (mThread != null) {
-            Log.e(TAG, "a recording is being done in parallel or stop is not called");
+    public synchronized void start() throws IllegalStateException {
+        if (mStarted) {
+            if (mThread == null) {
+                throw new IllegalStateException("Recording stopped and can't restart (single use)");
+            }
+            throw new IllegalStateException("Recording already started");
         }
+        mStarted = true;
         mAudioRecord.startRecording();
         if (mMic) mAudioRecordMic.startRecording();
         Log.d(TAG, "channel count " + mAudioRecord.getChannelCount());
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index a6cd350..344f0d2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -27,7 +27,6 @@
 import com.android.systemui.qs.QSFooterImpl;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QuickQSPanel;
-import com.android.systemui.qs.QuickStatusBarHeader;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
@@ -93,10 +92,6 @@
         }
 
         /**
-         * Creates the QuickStatusBarHeader.
-         */
-        QuickStatusBarHeader createQsHeader();
-        /**
          * Creates the QSFooterImpl.
          */
         QSFooterImpl createQsFooter();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index 1e969c2..fa78d1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -36,6 +36,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.Before;
@@ -65,6 +66,8 @@
     @Mock
     private ModeSwitchesController mModeSwitchesController;
     @Mock
+    private NavigationModeController mNavigationModeController;
+    @Mock
     private IRemoteMagnificationAnimationCallback mAnimationCallback;
     private IWindowMagnificationConnection mIWindowMagnificationConnection;
     private WindowMagnification mWindowMagnification;
@@ -79,7 +82,8 @@
         }).when(mAccessibilityManager).setWindowMagnificationConnection(
                 any(IWindowMagnificationConnection.class));
         mWindowMagnification = new WindowMagnification(getContext(),
-                getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
+                getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
+                mNavigationModeController);
         mWindowMagnification.mWindowMagnificationAnimationController =
                 mWindowMagnificationAnimationController;
         mWindowMagnification.requestWindowMagnificationConnection(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index c6440f4..5f2fd69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.accessibility;
 
 import static android.view.Choreographer.FrameCallback;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import static org.hamcrest.Matchers.containsString;
@@ -28,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
@@ -294,4 +296,15 @@
         assertTrue(
                 mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_left, null));
     }
+
+    @Test
+    public void onNavigationModeChanged_updateMirrorViewLayout() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.onNavigationModeChanged(NAV_BAR_MODE_GESTURAL);
+        });
+
+        verify(mWindowManager).updateViewLayout(eq(mMirrorView), any());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 936558b..4a0e216 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -35,6 +35,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.Before;
@@ -53,6 +54,8 @@
     private AccessibilityManager mAccessibilityManager;
     @Mock
     private ModeSwitchesController mModeSwitchesController;
+    @Mock
+    private NavigationModeController mNavigationModeController;
     private CommandQueue mCommandQueue;
     private WindowMagnification mWindowMagnification;
 
@@ -63,7 +66,8 @@
 
         mCommandQueue = new CommandQueue(getContext());
         mWindowMagnification = new WindowMagnification(getContext(),
-                getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
+                getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
+                mNavigationModeController);
         mWindowMagnification.start();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index ca328fb..9ebb587 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -36,6 +36,7 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.phone.ShadeController;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -73,6 +74,11 @@
         when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
     }
 
+    @After
+    public void tearDown() {
+        mMediaOutputDialog.dismissDialog();
+    }
+
     @Test
     public void getStopButtonVisibility_remoteDevice_returnVisible() {
         mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 1c2d0840..e472cb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -37,7 +37,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.CarrierText;
 import com.android.systemui.Dependency;
-import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -116,11 +115,6 @@
 
         qs.setListening(false);
         processAllMessages();
-
-        // Manually push header through detach so it can handle standard cleanup it does on
-        // removed from window.
-        ((QuickStatusBarHeader) qs.getView().findViewById(R.id.header)).onDetachedFromWindow();
-
         host.destroy();
         processAllMessages();
     }
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 915c2f6..613d28b 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -102,6 +102,7 @@
     ],
     libs: [
         "framework-tethering",
+        "framework-wifi",
     ],
     jarjar_rules: "jarjar-rules.txt",
     optimize: {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index fd9e360..b285849 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,6 +15,7 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
 
 import static java.util.Arrays.asList;
@@ -23,7 +24,6 @@
 import android.net.ConnectivityManager;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.net.Network;
 import android.net.ip.IpServer;
 import android.net.util.PrefixUtils;
@@ -90,16 +90,24 @@
 
     /**
      * Record a new upstream IpPrefix which may conflict with tethering downstreams.
-     * The downstreams will be notified if a conflict is found.
+     * The downstreams will be notified if a conflict is found. When updateUpstreamPrefix is called,
+     * UpstreamNetworkState must have an already populated LinkProperties.
      */
-    public void updateUpstreamPrefix(final Network network, final LinkProperties lp) {
-        final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(lp.getAllLinkAddresses());
-        if (ipv4Prefixes.isEmpty()) {
-            removeUpstreamPrefix(network);
+    public void updateUpstreamPrefix(final UpstreamNetworkState ns) {
+        // Do not support VPN as upstream
+        if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+            removeUpstreamPrefix(ns.network);
             return;
         }
 
-        mUpstreamPrefixMap.put(network, ipv4Prefixes);
+        final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(
+                ns.linkProperties.getAllLinkAddresses());
+        if (ipv4Prefixes.isEmpty()) {
+            removeUpstreamPrefix(ns.network);
+            return;
+        }
+
+        mUpstreamPrefixMap.put(ns.network, ipv4Prefixes);
         handleMaybePrefixConflict(ipv4Prefixes);
     }
 
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 64d5025..474f4e8 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -1678,14 +1678,6 @@
             }
         }
 
-        private void addUpstreamPrefixes(final UpstreamNetworkState ns) {
-            mPrivateAddressCoordinator.updateUpstreamPrefix(ns.network, ns.linkProperties);
-        }
-
-        private void removeUpstreamPrefixes(final UpstreamNetworkState ns) {
-            mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
-        }
-
         @VisibleForTesting
         void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
             if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
@@ -1696,10 +1688,10 @@
             final UpstreamNetworkState ns = (UpstreamNetworkState) o;
             switch (arg1) {
                 case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
-                    addUpstreamPrefixes(ns);
+                    mPrivateAddressCoordinator.updateUpstreamPrefix(ns);
                     break;
                 case UpstreamNetworkMonitor.EVENT_ON_LOST:
-                    removeUpstreamPrefixes(ns);
+                    mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
                     break;
             }
 
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 8e93c2e..7b6632c 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.TetheringManager.TETHERING_ETHERNET;
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
@@ -30,13 +34,12 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
-import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.net.ip.IpServer;
-import android.net.util.NetworkConstants;
 import android.net.util.PrefixUtils;
 
 import androidx.test.filters.SmallTest;
@@ -48,13 +51,10 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.List;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public final class PrivateAddressCoordinatorTest {
-    private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
-    private static final String TEST_WIFI_IFNAME = "test_wlan0";
+    private static final String TEST_IFNAME = "test0";
 
     @Mock private IpServer mHotspotIpServer;
     @Mock private IpServer mUsbIpServer;
@@ -69,7 +69,8 @@
     private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
     private final Network mWifiNetwork = new Network(1);
     private final Network mMobileNetwork = new Network(2);
-    private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
+    private final Network mVpnNetwork = new Network(3);
+    private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork};
 
     private void setUpIpServers() throws Exception {
         when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
@@ -184,33 +185,25 @@
         assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix);
     }
 
-    private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6,
-            boolean isMobile) {
-        final String testIface;
-        final String testIpv4Address;
-        if (isMobile) {
-            testIface = TEST_MOBILE_IFNAME;
-            testIpv4Address = "10.0.0.1";
-        } else {
-            testIface = TEST_WIFI_IFNAME;
-            testIpv4Address = "192.168.43.5";
-        }
-
+    private UpstreamNetworkState buildUpstreamNetworkState(final Network network,
+            final LinkAddress v4Addr, final LinkAddress v6Addr, final NetworkCapabilities cap) {
         final LinkProperties prop = new LinkProperties();
-        prop.setInterfaceName(testIface);
+        prop.setInterfaceName(TEST_IFNAME);
+        if (v4Addr != null) prop.addLinkAddress(v4Addr);
 
-        if (withIPv4) {
-            prop.addLinkAddress(
-                    new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address),
-                            NetworkConstants.IPV4_ADDR_BITS));
+        if (v6Addr != null) prop.addLinkAddress(v6Addr);
+
+        return new UpstreamNetworkState(prop, cap, network);
+    }
+
+    private NetworkCapabilities makeNetworkCapabilities(final int transportType) {
+        final NetworkCapabilities cap = new NetworkCapabilities();
+        cap.addTransportType(transportType);
+        if (transportType == TRANSPORT_VPN) {
+            cap.removeCapability(NET_CAPABILITY_NOT_VPN);
         }
 
-        if (withIPv6) {
-            prop.addLinkAddress(
-                    new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"),
-                            NetworkConstants.RFC7421_PREFIX_LENGTH));
-        }
-        return prop;
+        return cap;
     }
 
     @Test
@@ -220,53 +213,76 @@
         final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
         // Force always get subAddress "43.5" for conflict testing.
         when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
-        // 1. Enable hotspot with prefix 192.168.43.0/24
+        // - Enable hotspot with prefix 192.168.43.0/24
         final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
                 mHotspotIpServer);
         final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr);
         assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
         when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr);
-        // 2. Update v6 only mobile network, hotspot prefix should not be removed.
-        List<String> testConflicts;
-        final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true);
-        mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp);
+        // - test mobile network with null NetworkCapabilities. Ideally this should not happen,
+        // just make sure no crash in this case.
+        final UpstreamNetworkState noCapUpstream = buildUpstreamNetworkState(mMobileNetwork,
+                new LinkAddress("10.0.0.8/24"), null, null);
+        mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream);
+        verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+        // - test mobile upstream with no address.
+        final UpstreamNetworkState noAddress = buildUpstreamNetworkState(mMobileNetwork,
+                null, null, makeNetworkCapabilities(TRANSPORT_CELLULAR));
+        mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream);
+        verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+        // - Update v6 only mobile network, hotspot prefix should not be removed.
+        final UpstreamNetworkState v6OnlyMobile = buildUpstreamNetworkState(mMobileNetwork,
+                null, new LinkAddress("2001:db8::/64"),
+                makeNetworkCapabilities(TRANSPORT_CELLULAR));
+        mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyMobile);
         verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
         mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork);
-        // 3. Update v4 only mobile network, hotspot prefix should not be removed.
-        final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true);
-        mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp);
+        // - Update v4 only mobile network, hotspot prefix should not be removed.
+        final UpstreamNetworkState v4OnlyMobile = buildUpstreamNetworkState(mMobileNetwork,
+                new LinkAddress("10.0.0.8/24"), null,
+                makeNetworkCapabilities(TRANSPORT_CELLULAR));
+        mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyMobile);
         verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
-        // 4. Update v4v6 mobile network, hotspot prefix should not be removed.
-        final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true);
-        mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp);
+        // - Update v4v6 mobile network, hotspot prefix should not be removed.
+        final UpstreamNetworkState v4v6Mobile = buildUpstreamNetworkState(mMobileNetwork,
+                new LinkAddress("10.0.0.8/24"), new LinkAddress("2001:db8::/64"),
+                makeNetworkCapabilities(TRANSPORT_CELLULAR));
+        mPrivateAddressCoordinator.updateUpstreamPrefix(v4v6Mobile);
         verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
-        // 5. Update v6 only wifi network, hotspot prefix should not be removed.
-        final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false);
-        mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp);
+        // - Update v6 only wifi network, hotspot prefix should not be removed.
+        final UpstreamNetworkState v6OnlyWifi = buildUpstreamNetworkState(mWifiNetwork,
+                null, new LinkAddress("2001:db8::/64"), makeNetworkCapabilities(TRANSPORT_WIFI));
+        mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyWifi);
         verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
         mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
-        // 6. Update v4 only wifi network, it conflict with hotspot prefix.
-        final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false);
-        mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp);
+        // - Update vpn network, it conflict with hotspot prefix but VPN networks are ignored.
+        final UpstreamNetworkState v4OnlyVpn = buildUpstreamNetworkState(mVpnNetwork,
+                new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_VPN));
+        mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyVpn);
+        verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+        // - Update v4 only wifi network, it conflict with hotspot prefix.
+        final UpstreamNetworkState v4OnlyWifi = buildUpstreamNetworkState(mWifiNetwork,
+                new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_WIFI));
+        mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
         verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
         reset(mHotspotIpServer);
-        // 7. Restart hotspot again and its prefix is different previous.
+        // - Restart hotspot again and its prefix is different previous.
         mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
         final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress(
                 mHotspotIpServer);
         final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2);
         assertNotEquals(hotspotPrefix, hotspotPrefix2);
         when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2);
-        mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp);
+        mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
         verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
-        // 7. Usb tethering can be enabled and its prefix is different with conflict one.
+        // - Usb tethering can be enabled and its prefix is different with conflict one.
         final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
                 mUsbIpServer);
         final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr);
         assertNotEquals(predefinedPrefix, usbPrefix);
         assertNotEquals(hotspotPrefix2, usbPrefix);
         when(mUsbIpServer.getAddress()).thenReturn(usbAddr);
-        // 8. Disable wifi upstream, then wifi's prefix can be selected again.
+        // - Disable wifi upstream, then wifi's prefix can be selected again.
         mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
         final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
                 mEthernetIpServer);
diff --git a/services/Android.bp b/services/Android.bp
index ef52c2a..25a0d7e 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -3,6 +3,12 @@
     plugins: [
         "error_prone_android_framework",
     ],
+    errorprone: {
+        javacflags: [
+            "-Xep:AndroidFrameworkCompatChange:ERROR",
+            "-Xep:AndroidFrameworkUid:ERROR",
+        ],
+    },
 }
 
 filegroup {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 6d77486..2d87b7c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -18,9 +18,7 @@
 
 import static android.Manifest.permission.ACCESS_MTP;
 import static android.Manifest.permission.INSTALL_PACKAGES;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
@@ -4236,19 +4234,9 @@
             }
 
             // Determine if caller is holding runtime permission
-            final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
-                    uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
             final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
                     uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
 
-            // We're only willing to give out broad access if they also hold
-            // runtime permission; this is a firm CDD requirement
-            final boolean hasFull = mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE,
-                    uid) == PERMISSION_GRANTED;
-            if (hasFull && hasWrite) {
-                return Zygote.MOUNT_EXTERNAL_FULL;
-            }
-
             // We're only willing to give out installer access if they also hold
             // runtime permission; this is a firm CDD requirement
             final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
@@ -4268,19 +4256,7 @@
             if ((hasInstall || hasInstallOp) && hasWrite) {
                 return Zygote.MOUNT_EXTERNAL_INSTALLER;
             }
-
-            // Otherwise we're willing to give out sandboxed or non-sandboxed if
-            // they hold the runtime permission
-            boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
-                    uid, packageName) == MODE_ALLOWED;
-
-            if (hasLegacy && hasWrite) {
-                return Zygote.MOUNT_EXTERNAL_WRITE;
-            } else if (hasLegacy && hasRead) {
-                return Zygote.MOUNT_EXTERNAL_READ;
-            } else {
-                return Zygote.MOUNT_EXTERNAL_DEFAULT;
-            }
+            return Zygote.MOUNT_EXTERNAL_DEFAULT;
         } catch (RemoteException e) {
             // Should not happen
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ffdcd15..d3f4667 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -153,7 +153,6 @@
 import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
-import android.app.IAssistDataReceiver;
 import android.app.IInstrumentationWatcher;
 import android.app.INotificationManager;
 import android.app.IProcessObserver;
@@ -286,7 +285,6 @@
 import android.util.proto.ProtoUtils;
 import android.view.Display;
 import android.view.Gravity;
-import android.view.IRecentsAnimationRunner;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
@@ -2840,18 +2838,6 @@
         return mActivityTaskManager.startActivityFromRecents(taskId, bOptions);
     }
 
-    @Override
-    public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
-            IRecentsAnimationRunner recentsAnimationRunner) {
-        mActivityTaskManager.startRecentsActivity(
-                intent, assistDataReceiver, recentsAnimationRunner);
-    }
-
-    @Override
-    public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
-        mActivityTaskManager.cancelRecentsAnimation(restoreHomeStackPosition);
-    }
-
     /**
      * This is the internal entry point for handling Activity.finish().
      *
@@ -16492,7 +16478,7 @@
         @Override
         public int getStorageMountMode(int pid, int uid) {
             if (uid == SHELL_UID || uid == ROOT_UID) {
-                return Zygote.MOUNT_EXTERNAL_FULL;
+                return Zygote.MOUNT_EXTERNAL_DEFAULT;
             }
             synchronized (mPidsSelfLocked) {
                 final ProcessRecord pr = mPidsSelfLocked.get(pid);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 5e65563..ed47616d9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -92,7 +92,6 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
 import android.system.Os;
 import android.text.TextUtils;
@@ -1780,14 +1779,10 @@
                     final IPackageManager pm = AppGlobals.getPackageManager();
                     permGids = pm.getPackageGids(app.info.packageName,
                             MATCH_DIRECT_BOOT_AUTO, app.userId);
-                    if (StorageManager.hasIsolatedStorage() && mountExtStorageFull) {
-                        mountExternal = Zygote.MOUNT_EXTERNAL_FULL;
-                    } else {
-                        StorageManagerInternal storageManagerInternal = LocalServices.getService(
-                                StorageManagerInternal.class);
-                        mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
-                                app.info.packageName);
-                    }
+                    StorageManagerInternal storageManagerInternal = LocalServices.getService(
+                            StorageManagerInternal.class);
+                    mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
+                            app.info.packageName);
                 } catch (RemoteException e) {
                     throw e.rethrowAsRuntimeException();
                 }
@@ -1918,7 +1913,9 @@
 
             String instructionSet = null;
             if (app.info.primaryCpuAbi != null) {
-                instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
+                // If ABI override is specified, use the isa derived from the value of ABI override.
+                // Otherwise, use the isa derived from primary ABI
+                instructionSet = VMRuntime.getInstructionSet(requiredAbi);
             }
 
             app.gids = gids;
@@ -1927,7 +1924,7 @@
 
             // If instructionSet is non-null, this indicates that the system_server is spawning a
             // process with an ISA that may be different from its own. System (kernel and hardware)
-            // compatililty for these features is checked in the decideTaggingLevel in the
+            // compatibility for these features is checked in the decideTaggingLevel in the
             // system_server process (not the child process). As both MTE and TBI are only supported
             // in aarch64, we can simply ensure that the new process is also aarch64. This prevents
             // the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index c1777b8..7dbb39e 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1709,24 +1709,13 @@
                             if (Process.isIsolated(uid)) {
                                 return Zygote.MOUNT_EXTERNAL_NONE;
                             }
-                            if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
-                                    packageName, null, true, "External storage policy", true)
-                                    != AppOpsManager.MODE_ALLOWED) {
-                                return Zygote.MOUNT_EXTERNAL_NONE;
-                            }
-                            if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
-                                    packageName, null, true, "External storage policy", true)
-                                    != AppOpsManager.MODE_ALLOWED) {
-                                return Zygote.MOUNT_EXTERNAL_READ;
-                            }
-                            return Zygote.MOUNT_EXTERNAL_WRITE;
+                            return Zygote.MOUNT_EXTERNAL_DEFAULT;
                         }
 
                         @Override
                         public boolean hasExternalStorage(int uid, String packageName) {
                             final int mountMode = getMountMode(uid, packageName);
-                            return mountMode == Zygote.MOUNT_EXTERNAL_READ
-                                    || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
+                            return mountMode != Zygote.MOUNT_EXTERNAL_NONE;
                         }
                     });
         }
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 92c498c..bac944f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -27,8 +27,6 @@
 
     private static final String TAG = "GenerateChallengeClient";
 
-    protected long mChallenge;
-
     public GenerateChallengeClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
             @NonNull String owner, int sensorId) {
@@ -51,12 +49,5 @@
         super.start(callback);
 
         startHalOperation();
-        try {
-            getListener().onChallengeGenerated(getSensorId(), mChallenge);
-            mCallback.onClientFinished(this, true /* success */);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Remote exception", e);
-            mCallback.onClientFinished(this, false /* success */);
-        }
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
index ba401f2..406a7cc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
@@ -59,7 +59,14 @@
     @Override
     protected void startHalOperation() {
         try {
-            mChallenge = getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
+            final long challenge = getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
+            try {
+                getListener().onChallengeGenerated(getSensorId(), challenge);
+                mCallback.onClientFinished(this, true /* success */);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception", e);
+                mCallback.onClientFinished(this, false /* success */);
+            }
         } catch (RemoteException e) {
             Slog.e(TAG, "generateChallenge failed", e);
         }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
index abaaac5..5169c7d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
@@ -45,7 +45,14 @@
     @Override
     protected void startHalOperation() {
         try {
-            mChallenge = getFreshDaemon().preEnroll();
+            final long challenge = getFreshDaemon().preEnroll();
+            try {
+                getListener().onChallengeGenerated(getSensorId(), challenge);
+                mCallback.onClientFinished(this, true /* success */);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception", e);
+                mCallback.onClientFinished(this, false /* success */);
+            }
         } catch (RemoteException e) {
             Slog.e(TAG, "preEnroll failed", e);
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index bb6f14c..96679c3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.tv.cec.V1_0.CecMessage;
 import android.hardware.tv.cec.V1_0.HotplugEvent;
@@ -774,6 +776,7 @@
         private IHdmiCec mHdmiCec;
         private final Object mLock = new Object();
         private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+        @Nullable private HdmiCecCallback mCallback;
 
         @Override
         public String nativeInit() {
@@ -782,7 +785,7 @@
 
         boolean connectToHal() {
             try {
-                mHdmiCec = IHdmiCec.getService();
+                mHdmiCec = IHdmiCec.getService(true);
                 try {
                     mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE);
                 } catch (RemoteException e) {
@@ -796,7 +799,8 @@
         }
 
         @Override
-        public void setCallback(HdmiCecCallback callback) {
+        public void setCallback(@NonNull HdmiCecCallback callback) {
+            mCallback = callback;
             try {
                 mHdmiCec.setCallback(callback);
             } catch (RemoteException e) {
@@ -936,6 +940,10 @@
             if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
                 HdmiLogger.error("Service died cookie : " + cookie + "; reconnecting");
                 connectToHal();
+                // Reconnect the callback
+                if (mCallback != null) {
+                    setCallback(mCallback);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 68473c1..29bdd6c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -379,7 +379,8 @@
         assertRunOnServiceThread();
         if (reason == mService.INITIATED_BY_ENABLE_CEC) {
             mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
-                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST,
+                    "HdmiCecLocalDeviceAudioSystem#onAddressAllocated()");
         }
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
@@ -1324,7 +1325,8 @@
         if (getRoutingPort() == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
             routeToInputFromPortId(Constants.CEC_SWITCH_HOME);
             mService.setAndBroadcastActiveSourceFromOneDeviceType(
-                    message.getSource(), mService.getPhysicalAddress());
+                    message.getSource(), mService.getPhysicalAddress(),
+                    "HdmiCecLocalDeviceAudioSystem#handleRoutingChangeAndInformationForSwitch()");
             return;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 6e6d848..6257032 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.CallSuper;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
@@ -96,7 +97,8 @@
         assertRunOnServiceThread();
         if (reason == mService.INITIATED_BY_ENABLE_CEC) {
             mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
-                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST,
+                    "HdmiCecLocalDevicePlayback#onAddressAllocated()");
         }
         mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, mService.getPhysicalAddress(), mDeviceType));
@@ -165,7 +167,7 @@
     void onHotplug(int portId, boolean connected) {
         assertRunOnServiceThread();
         mCecMessageCache.flushAll();
-        // We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
+        // We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3.
         if (!connected) {
             getWakeLock().release();
         }
@@ -178,13 +180,12 @@
         if (!mService.isControlEnabled()) {
             return;
         }
-        if (mIsActiveSource) {
+        if (isActiveSource()) {
             mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
                     mAddress, mService.getPhysicalAddress()));
         }
-        boolean wasActiveSource = mIsActiveSource;
+        boolean wasActiveSource = isActiveSource();
         // Invalidate the internal active source record when goes to standby
-        // This set will also update mIsActiveSource
         mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
                 "HdmiCecLocalDevicePlayback#onStandby()");
         if (initiatedByCec || !mAutoTvOff || !wasActiveSource) {
@@ -229,12 +230,13 @@
     }
 
     @Override
+    @CallSuper
     @ServiceThreadOnly
     @VisibleForTesting
-    void setIsActiveSource(boolean on) {
+    protected void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
         assertRunOnServiceThread();
-        super.setIsActiveSource(on);
-        if (on) {
+        super.setActiveSource(logicalAddress, physicalAddress, caller);
+        if (isActiveSource()) {
             getWakeLock().acquire();
         } else {
             getWakeLock().release();
@@ -291,7 +293,7 @@
 
     @Override
     protected void wakeUpIfActiveSource() {
-        if (!mIsActiveSource) {
+        if (!isActiveSource()) {
             return;
         }
         // Wake up the device if the power is in standby mode, or its screen is off -
@@ -399,9 +401,16 @@
                     "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
             return;
         }
+        if (!isActiveSource()) {
+            // If routing is changed to the device while Active Source, don't invalidate the
+            // Active Source
+            setActiveSource(physicalAddress,
+                    "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
+        }
         switch (mPlaybackDeviceActionOnRoutingControl) {
             case WAKE_UP_AND_SEND_ACTIVE_SOURCE:
-                setAndBroadcastActiveSource(message, physicalAddress);
+                setAndBroadcastActiveSource(message, physicalAddress,
+                        "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
                 break;
             case WAKE_UP_ONLY:
                 mService.wakeUp();
@@ -436,7 +445,7 @@
     @Override
     protected void dump(final IndentingPrintWriter pw) {
         super.dump(pw);
-        pw.println("mIsActiveSource: " + mIsActiveSource);
+        pw.println("isActiveSource(): " + isActiveSource());
         pw.println("mAutoTvOff:" + mAutoTvOff);
     }
 
@@ -457,7 +466,7 @@
         @Override
         public void acquire() {
             mWakeLock.acquire();
-            HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
+            HdmiLogger.debug("active source: %b. Wake lock acquired", isActiveSource());
         }
 
         @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 4ff36c4..4325f79 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.CallSuper;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
@@ -36,10 +37,6 @@
 
     private static final String TAG = "HdmiCecLocalDeviceSource";
 
-    // Indicate if current device is Active Source or not
-    @VisibleForTesting
-    protected boolean mIsActiveSource = false;
-
     // Device has cec switch functionality or not.
     // Default is false.
     protected boolean mIsSwitchDevice = HdmiProperties.is_switch().orElse(false);
@@ -78,7 +75,7 @@
         if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
             mCecMessageCache.flushAll();
         }
-        // We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
+        // We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3.
         if (connected) {
             mService.wakeUp();
         }
@@ -118,10 +115,21 @@
         // Nothing to do.
     }
 
+    @Override
+    @CallSuper
+    @ServiceThreadOnly
+    void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
+        boolean wasActiveSource = isActiveSource();
+        super.setActiveSource(logicalAddress, physicalAddress, caller);
+        if (wasActiveSource && !isActiveSource()) {
+            onActiveSourceLost();
+        }
+    }
+
     @ServiceThreadOnly
     protected void setActiveSource(int physicalAddress, String caller) {
         assertRunOnServiceThread();
-        // Invalidate the internal active source record. This will also update mIsActiveSource.
+        // Invalidate the internal active source record.
         ActiveSource activeSource = ActiveSource.of(Constants.ADDR_INVALID, physicalAddress);
         setActiveSource(activeSource, caller);
     }
@@ -135,7 +143,6 @@
         if (!getActiveSource().equals(activeSource)) {
             setActiveSource(activeSource, "HdmiCecLocalDeviceSource#handleActiveSource()");
         }
-        setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
         updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
         if (isRoutingControlFeatureEnabled()) {
             switchInputOnReceivingNewActivePath(physicalAddress);
@@ -159,9 +166,11 @@
         // If current device is the target path, set to Active Source.
         // If the path is under the current device, should switch
         if (physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) {
-            setAndBroadcastActiveSource(message, physicalAddress);
-        }
-        if (physicalAddress != mService.getPhysicalAddress()) {
+            setAndBroadcastActiveSource(message, physicalAddress,
+                    "HdmiCecLocalDeviceSource#handleSetStreamPath()");
+        } else if (physicalAddress != mService.getPhysicalAddress() || !isActiveSource()) {
+            // Invalidate the active source if stream path is set to other physical address or
+            // our physical address while not active source
             setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleSetStreamPath()");
         }
         switchInputOnReceivingNewActivePath(physicalAddress);
@@ -173,19 +182,15 @@
     protected boolean handleRoutingChange(HdmiCecMessage message) {
         assertRunOnServiceThread();
         int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2);
-        if (physicalAddress != mService.getPhysicalAddress()) {
+        if (physicalAddress != mService.getPhysicalAddress() || !isActiveSource()) {
+            // Invalidate the active source if routing is changed to other physical address or
+            // our physical address while not active source
             setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingChange()");
         }
         if (!isRoutingControlFeatureEnabled()) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
             return true;
         }
-        // if the current device is a pure playback device
-        if (!mIsSwitchDevice
-                && physicalAddress == mService.getPhysicalAddress()
-                && mService.isPlaybackDevice()) {
-            setAndBroadcastActiveSource(message, physicalAddress);
-        }
         handleRoutingChangeAndInformation(physicalAddress, message);
         return true;
     }
@@ -195,19 +200,15 @@
     protected boolean handleRoutingInformation(HdmiCecMessage message) {
         assertRunOnServiceThread();
         int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        if (physicalAddress != mService.getPhysicalAddress()) {
+        if (physicalAddress != mService.getPhysicalAddress() || !isActiveSource()) {
+            // Invalidate the active source if routing is changed to other physical address or
+            // our physical address while not active source
             setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingInformation()");
         }
         if (!isRoutingControlFeatureEnabled()) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
             return true;
         }
-        // if the current device is a pure playback device
-        if (!mIsSwitchDevice
-                && physicalAddress == mService.getPhysicalAddress()
-                && mService.isPlaybackDevice()) {
-            setAndBroadcastActiveSource(message, physicalAddress);
-        }
         handleRoutingChangeAndInformation(physicalAddress, message);
         return true;
     }
@@ -236,23 +237,21 @@
     // since service can decide who will be the active source when the device supports
     // multiple device types in this method.
     // This method should only be called when the device can be the active source.
-    protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
+    protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress,
+            String caller) {
         mService.setAndBroadcastActiveSource(
-                physicalAddress, getDeviceInfo().getDeviceType(), message.getSource());
+                physicalAddress, getDeviceInfo().getDeviceType(), message.getSource(), caller);
     }
 
+    // Indicates if current device is the active source or not
     @ServiceThreadOnly
-    void setIsActiveSource(boolean on) {
-        assertRunOnServiceThread();
-        boolean wasActiveSource = mIsActiveSource;
-        mIsActiveSource = on;
-        if (wasActiveSource && !mIsActiveSource) {
-            onActiveSourceLost();
-        }
+    protected boolean isActiveSource() {
+        return getActiveSource().equals(getDeviceInfo().getLogicalAddress(),
+                getDeviceInfo().getPhysicalAddress());
     }
 
     protected void wakeUpIfActiveSource() {
-        if (!mIsActiveSource) {
+        if (!isActiveSource()) {
             return;
         }
         // Wake up the device
@@ -261,7 +260,7 @@
     }
 
     protected void maySendActiveSource(int dest) {
-        if (!mIsActiveSource) {
+        if (!isActiveSource()) {
             return;
         }
         addAndStartAction(new ActiveSourceAction(this, dest));
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b407234..a60a676 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1600,7 +1600,7 @@
                 if (isPlaybackDevice()) {
                     // if playback device itself is the active source,
                     // return its own device info.
-                    if (playback() != null && playback().mIsActiveSource) {
+                    if (playback() != null && playback().isActiveSource()) {
                         return playback().getDeviceInfo();
                     }
                     // Otherwise get the active source and look for it from the device list
@@ -3242,20 +3242,12 @@
                 HdmiUtils.pathRelationship(getPhysicalAddress(), physicalAddress));
 
         // If the current device is a source device, check if the current Active Source matches
-        // the local device info. Set mIsActiveSource of the local device accordingly.
+        // the local device info.
         for (HdmiCecLocalDevice device : getAllLocalDevices()) {
-            // mIsActiveSource only exists in source device, ignore this setting if the current
-            // device is not an HdmiCecLocalDeviceSource.
-            if (!(device instanceof HdmiCecLocalDeviceSource)) {
-                device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
-                        false, caller);
-                continue;
-            }
             boolean deviceIsActiveSource =
                     logicalAddress == device.getDeviceInfo().getLogicalAddress()
                             && physicalAddress == getPhysicalAddress();
 
-            ((HdmiCecLocalDeviceSource) device).setIsActiveSource(deviceIsActiveSource);
             device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
                     deviceIsActiveSource, caller);
         }
@@ -3266,22 +3258,22 @@
     // For example, when receiving broadcast messages, all the device types will call this
     // method but only one of them will be the Active Source.
     protected void setAndBroadcastActiveSource(
-            int physicalAddress, int deviceType, int source) {
+            int physicalAddress, int deviceType, int source, String caller) {
         // If the device has both playback and audio system logical addresses,
         // playback will claim active source. Otherwise audio system will.
         if (deviceType == HdmiDeviceInfo.DEVICE_PLAYBACK) {
             HdmiCecLocalDevicePlayback playback = playback();
-            playback.setIsActiveSource(true);
+            playback.setActiveSource(playback.getDeviceInfo().getLogicalAddress(), physicalAddress,
+                    caller);
             playback.wakeUpIfActiveSource();
             playback.maySendActiveSource(source);
         }
 
         if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
             HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
-            if (playback() != null) {
-                audioSystem.setIsActiveSource(false);
-            } else {
-                audioSystem.setIsActiveSource(true);
+            if (playback() == null) {
+                audioSystem.setActiveSource(audioSystem.getDeviceInfo().getLogicalAddress(),
+                        physicalAddress, caller);
                 audioSystem.wakeUpIfActiveSource();
                 audioSystem.maySendActiveSource(source);
             }
@@ -3294,24 +3286,21 @@
     // and this method updates Active Source in all the device types sharing the same
     // Physical Address.
     protected void setAndBroadcastActiveSourceFromOneDeviceType(
-            int sourceAddress, int physicalAddress) {
+            int sourceAddress, int physicalAddress, String caller) {
         // If the device has both playback and audio system logical addresses,
         // playback will claim active source. Otherwise audio system will.
         HdmiCecLocalDevicePlayback playback = playback();
         HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
         if (playback != null) {
-            playback.setIsActiveSource(true);
+            playback.setActiveSource(playback.getDeviceInfo().getLogicalAddress(), physicalAddress,
+                    caller);
             playback.wakeUpIfActiveSource();
             playback.maySendActiveSource(sourceAddress);
-            if (audioSystem != null) {
-                audioSystem.setIsActiveSource(false);
-            }
-        } else {
-            if (audioSystem != null) {
-                audioSystem.setIsActiveSource(true);
-                audioSystem.wakeUpIfActiveSource();
-                audioSystem.maySendActiveSource(sourceAddress);
-            }
+        } else if (audioSystem != null) {
+            audioSystem.setActiveSource(audioSystem.getDeviceInfo().getLogicalAddress(),
+                    physicalAddress, caller);
+            audioSystem.wakeUpIfActiveSource();
+            audioSystem.maySendActiveSource(sourceAddress);
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 4962af1..e78a86c 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -85,7 +85,7 @@
         // Because only source device can create this action, it's safe to cast.
         HdmiCecLocalDeviceSource source = source();
         source.mService.setAndBroadcastActiveSourceFromOneDeviceType(
-                mTargetAddress, getSourcePath());
+                mTargetAddress, getSourcePath(), "OneTouchPlayAction#broadcastActiveSource()");
         // When OneTouchPlay is called, client side should be responsible to send out the intent
         // of which internal source, for example YouTube, it would like to switch to.
         // Here we only update the active port and the active source records in the local
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index 0907e5d..acafda6 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -119,7 +119,8 @@
         // claim Active Source and start to query TV system audio mode support.
         if (audioSystem().mService.isPlaybackDevice()) {
             audioSystem().mService.setAndBroadcastActiveSourceFromOneDeviceType(
-                    Constants.ADDR_BROADCAST, getSourcePath());
+                    Constants.ADDR_BROADCAST, getSourcePath(),
+                    "SystemAudioInitiationActionFromAvr#handleActiveSourceTimeout()");
             mState = STATE_WAITING_FOR_TV_SUPPORT;
             queryTvSystemAudioModeSupport();
         } else {
diff --git a/services/core/java/com/android/server/location/timezone/ControllerImpl.java b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
index 99414c4..d482637 100644
--- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java
+++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
@@ -44,16 +44,22 @@
 import java.util.Objects;
 
 /**
- * A real implementation of {@link LocationTimeZoneProviderController} that supports a single
- * {@link LocationTimeZoneProvider}.
+ * A real implementation of {@link LocationTimeZoneProviderController} that supports a primary and a
+ * secondary {@link LocationTimeZoneProvider}.
  *
- * TODO(b/152744911): This implementation currently only supports a single ("primary") provider.
- *  Support for a secondary provider will be added in a later commit.
+ * <p>The primary is used until it fails or becomes uncertain. The secondary will then be enabled.
+ * The controller will immediately make suggestions based on "certain" {@link
+ * LocationTimeZoneEvent}s, i.e. events that demonstrate the provider is certain what the time zone
+ * is. The controller will not make immediate suggestions based on "uncertain" events, giving
+ * providers time to change their mind. This also gives the secondary provider time to initialize
+ * when the primary becomes uncertain.
  */
 class ControllerImpl extends LocationTimeZoneProviderController {
 
     @NonNull private final LocationTimeZoneProvider mPrimaryProvider;
 
+    @NonNull private final LocationTimeZoneProvider mSecondaryProvider;
+
     @GuardedBy("mSharedLock")
     // Non-null after initialize()
     private ConfigurationInternal mCurrentUserConfiguration;
@@ -67,7 +73,9 @@
     private Callback mCallback;
 
     /**
-     * Used for scheduling uncertainty timeouts, i.e after the provider has reported uncertainty.
+     * Used for scheduling uncertainty timeouts, i.e after a provider has reported uncertainty.
+     * This timeout is not provider-specific: it is started when the controller becomes uncertain
+     * due to events it has received from one or other provider.
      */
     @NonNull private final SingleRunnableQueue mUncertaintyTimeoutQueue;
 
@@ -77,10 +85,12 @@
     private GeolocationTimeZoneSuggestion mLastSuggestion;
 
     ControllerImpl(@NonNull ThreadingDomain threadingDomain,
-            @NonNull LocationTimeZoneProvider primaryProvider) {
+            @NonNull LocationTimeZoneProvider primaryProvider,
+            @NonNull LocationTimeZoneProvider secondaryProvider) {
         super(threadingDomain);
         mUncertaintyTimeoutQueue = threadingDomain.createSingleRunnableQueue();
         mPrimaryProvider = Objects.requireNonNull(primaryProvider);
+        mSecondaryProvider = Objects.requireNonNull(secondaryProvider);
     }
 
     @Override
@@ -96,8 +106,9 @@
             LocationTimeZoneProvider.ProviderListener providerListener =
                     ControllerImpl.this::onProviderStateChange;
             mPrimaryProvider.initialize(providerListener);
+            mSecondaryProvider.initialize(providerListener);
 
-            alterProviderEnabledStateIfRequired(
+            alterProvidersEnabledStateIfRequired(
                     null /* oldConfiguration */, mCurrentUserConfiguration);
         }
     }
@@ -115,15 +126,15 @@
 
             if (!newConfig.equals(oldConfig)) {
                 if (newConfig.getUserId() != oldConfig.getUserId()) {
-                    // If the user changed, disable the provider if needed. It may be re-enabled for
-                    // the new user below if their settings allow.
+                    // If the user changed, disable the providers if needed. They may be re-enabled
+                    // for the new user immediately afterwards if their settings allow.
                     debugLog("User changed. old=" + oldConfig.getUserId()
-                            + ", new=" + newConfig.getUserId() + ": Disabling provider");
-                    disableProvider();
+                            + ", new=" + newConfig.getUserId() + ": Disabling providers");
+                    disableProviders();
 
-                    alterProviderEnabledStateIfRequired(null /* oldConfiguration */, newConfig);
+                    alterProvidersEnabledStateIfRequired(null /* oldConfiguration */, newConfig);
                 } else {
-                    alterProviderEnabledStateIfRequired(oldConfig, newConfig);
+                    alterProvidersEnabledStateIfRequired(oldConfig, newConfig);
                 }
             }
         }
@@ -140,10 +151,11 @@
     }
 
     @GuardedBy("mSharedLock")
-    private void disableProvider() {
+    private void disableProviders() {
         disableProviderIfEnabled(mPrimaryProvider);
+        disableProviderIfEnabled(mSecondaryProvider);
 
-        // By definition, if the provider is disabled, the controller is uncertain.
+        // By definition, if both providers are disabled, the controller is uncertain.
         cancelUncertaintyTimeout();
     }
 
@@ -181,7 +193,7 @@
     }
 
     /**
-     * Sets the provider into the correct enabled/disabled state for the {@code newConfiguration}
+     * Sets the providers into the correct enabled/disabled state for the {@code newConfiguration}
      * and, if there is a provider state change, makes any suggestions required to inform the
      * downstream time zone detection code.
      *
@@ -190,7 +202,7 @@
      * or when a new configuration has been received.
      */
     @GuardedBy("mSharedLock")
-    private void alterProviderEnabledStateIfRequired(
+    private void alterProvidersEnabledStateIfRequired(
             @Nullable ConfigurationInternal oldConfiguration,
             @NonNull ConfigurationInternal newConfiguration) {
 
@@ -203,21 +215,40 @@
             return;
         }
 
+        // The check above ensures that the logic below only executes if providers are going from
+        // {enabled *} -> {disabled}, or {disabled} -> {enabled initializing}. If this changes in
+        // future and there could be {enabled *} -> {enabled *} cases, or cases where the provider
+        // can't be assumed to go straight to the {enabled initializing} state, then the logic below
+        // would need to cover extra conditions, for example:
+        // 1) If the primary is in {enabled uncertain}, the secondary should be enabled.
+        // 2) If (1), and the secondary instantly enters the {perm failed} state, the uncertainty
+        //    timeout started when the primary entered {enabled uncertain} should be cancelled.
+
         if (newGeoDetectionEnabled) {
             // Try to enable the primary provider.
             tryEnableProvider(mPrimaryProvider, newConfiguration);
 
+            // The secondary should only ever be enabled if the primary now isn't enabled (i.e. it
+            // couldn't become {enabled initializing} because it is {perm failed}).
             ProviderState newPrimaryState = mPrimaryProvider.getCurrentState();
             if (!newPrimaryState.isEnabled()) {
-                // If the provider is perm failed then the controller is immediately considered
-                // uncertain.
-                GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
-                        "Provider is failed:"
-                                + " primary=" + mPrimaryProvider.getCurrentState());
-                makeSuggestion(suggestion);
+                // If the primary provider is {perm failed} then the controller must try to enable
+                // the secondary.
+                tryEnableProvider(mSecondaryProvider, newConfiguration);
+
+                ProviderState newSecondaryState = mSecondaryProvider.getCurrentState();
+                if (!newSecondaryState.isEnabled()) {
+                    // If both providers are {perm failed} then the controller immediately
+                    // becomes uncertain.
+                    GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
+                            "Providers are failed:"
+                                    + " primary=" + mPrimaryProvider.getCurrentState()
+                                    + " secondary=" + mPrimaryProvider.getCurrentState());
+                    makeSuggestion(suggestion);
+                }
             }
         } else {
-            disableProvider();
+            disableProviders();
 
             // There can be an uncertainty timeout set if the controller most recently received
             // an uncertain event. This is a no-op if there isn't a timeout set.
@@ -300,35 +331,63 @@
     }
 
     private void assertProviderKnown(@NonNull LocationTimeZoneProvider provider) {
-        if (provider != mPrimaryProvider) {
+        if (provider != mPrimaryProvider && provider != mSecondaryProvider) {
             throw new IllegalArgumentException("Unknown provider: " + provider);
         }
     }
 
     /**
-     * Called when the provider has reported that it has failed permanently.
+     * Called when a provider has reported that it has failed permanently.
      */
     @GuardedBy("mSharedLock")
     private void handleProviderFailedStateChange(@NonNull ProviderState providerState) {
         LocationTimeZoneProvider failedProvider = providerState.provider;
+        ProviderState primaryCurrentState = mPrimaryProvider.getCurrentState();
+        ProviderState secondaryCurrentState = mSecondaryProvider.getCurrentState();
 
-        // If the provider is newly perm failed then the controller is uncertain by
-        // definition.
-        cancelUncertaintyTimeout();
+        // If a provider has failed, the other may need to be enabled.
+        if (failedProvider == mPrimaryProvider) {
+            if (secondaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
+                // The primary must have failed. Try to enable the secondary. This does nothing if
+                // the provider is already enabled, and will leave the provider in
+                // {enabled initializing} if the provider is disabled.
+                tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
+            }
+        } else if (failedProvider == mSecondaryProvider) {
+            // No-op: The secondary will only be active if the primary is uncertain or is failed.
+            // So, there the primary should not need to be enabled when the secondary fails.
+            if (primaryCurrentState.stateEnum != PROVIDER_STATE_ENABLED_UNCERTAIN
+                    && primaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
+                warnLog("Secondary provider unexpected reported a failure:"
+                        + " failed provider=" + failedProvider.getName()
+                        + ", primary provider=" + mPrimaryProvider
+                        + ", secondary provider=" + mSecondaryProvider);
+            }
+        }
 
-        // If the provider is now failed, then we must send a suggestion informing the time
-        // zone detector that there are no further updates coming in future.
+        // If both providers are now failed, the controller needs to tell the next component in the
+        // time zone detection process.
+        if (primaryCurrentState.stateEnum == PROVIDER_STATE_PERM_FAILED
+                && secondaryCurrentState.stateEnum == PROVIDER_STATE_PERM_FAILED) {
 
-        GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
-                "The provider is permanently failed:"
-                        + " provider=" + failedProvider);
-        makeSuggestion(suggestion);
+            // If both providers are newly failed then the controller is uncertain by definition
+            // and it will never recover so it can send a suggestion immediately.
+            cancelUncertaintyTimeout();
+
+            // If both providers are now failed, then a suggestion must be sent informing the time
+            // zone detector that there are no further updates coming in future.
+            GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
+                    "Both providers are permanently failed:"
+                            + " primary=" + primaryCurrentState.provider
+                            + ", secondary=" + secondaryCurrentState.provider);
+            makeSuggestion(suggestion);
+        }
     }
 
     /**
      * Called when a provider has changed state but just moved from one enabled state to another
      * enabled state, usually as a result of a new {@link LocationTimeZoneEvent} being received.
-     * However, there are rare cases where the event can be null.
+     * However, there are rare cases where the event can also be null.
      */
     @GuardedBy("mSharedLock")
     private void handleProviderEnabledStateChange(@NonNull ProviderState providerState) {
@@ -395,6 +454,10 @@
         // By definition, the controller is now certain.
         cancelUncertaintyTimeout();
 
+        if (provider == mPrimaryProvider) {
+            disableProviderIfEnabled(mSecondaryProvider);
+        }
+
         GeolocationTimeZoneSuggestion suggestion =
                 new GeolocationTimeZoneSuggestion(timeZoneIds);
         suggestion.addDebugInfo(reason);
@@ -421,6 +484,11 @@
             mPrimaryProvider.dump(ipw, args);
             ipw.decreaseIndent(); // level 2
 
+            ipw.println("Secondary Provider:");
+            ipw.increaseIndent(); // level 2
+            mSecondaryProvider.dump(ipw, args);
+            ipw.decreaseIndent(); // level 2
+
             ipw.decreaseIndent(); // level 1
         }
     }
@@ -470,6 +538,14 @@
             mUncertaintyTimeoutQueue.runDelayed(() -> onProviderUncertaintyTimeout(provider),
                     delay.toMillis());
         }
+
+        if (provider == mPrimaryProvider) {
+            // (Try to) enable the secondary. It could already be enabled, or enabling might not
+            // succeed if the provider has previously reported it is perm failed. The uncertainty
+            // timeout (set above) is used to ensure that an uncertain suggestion will be made if
+            // the secondary cannot generate a success event in time.
+            tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
+        }
     }
 
     private void onProviderUncertaintyTimeout(@NonNull LocationTimeZoneProvider provider) {
@@ -478,7 +554,8 @@
         synchronized (mSharedLock) {
             GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
                     "Uncertainty timeout triggered for " + provider.getName() + ":"
-                            + " primary=" + mPrimaryProvider);
+                            + " primary=" + mPrimaryProvider
+                            + ", secondary=" + mSecondaryProvider);
             makeSuggestion(suggestion);
         }
     }
@@ -498,6 +575,8 @@
         LocationTimeZoneProvider targetProvider;
         if (Objects.equals(mPrimaryProvider.getName(), targetProviderName)) {
             targetProvider = mPrimaryProvider;
+        } else if (Objects.equals(mSecondaryProvider.getName(), targetProviderName)) {
+            targetProvider = mSecondaryProvider;
         } else {
             warnLog("Unable to process simulated binder provider event,"
                     + " unknown providerName in event=" + event);
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index c9a211d..a8589d4 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -44,8 +44,8 @@
  * are made to the {@link TimeZoneDetectorInternal}, and the {@link LocationTimeZoneProvider}s that
  * offer {@link android.location.timezone.LocationTimeZoneEvent}s.
  *
- * TODO(b/152744911): This implementation currently only supports a primary provider. Support for a
- *  secondary provider must be added in a later commit.
+ * <p>For details of the time zone suggestion behavior, see {@link
+ * LocationTimeZoneProviderController}.
  *
  * <p>Implementation details:
  *
@@ -109,6 +109,7 @@
     static final String TAG = "LocationTZDetector";
 
     static final String PRIMARY_PROVIDER_NAME = "primary";
+    static final String SECONDARY_PROVIDER_NAME = "secondary";
 
     private static final String SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX =
             "persist.sys.location_tz_simulation_mode.";
@@ -117,6 +118,8 @@
 
     private static final String PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
             "com.android.location.timezone.service.v1.PrimaryLocationTimeZoneProvider";
+    private static final String SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
+            "com.android.location.timezone.service.v1.SecondaryLocationTimeZoneProvider";
 
 
     @NonNull private final Context mContext;
@@ -160,8 +163,9 @@
         // Called on an arbitrary thread during initialization.
         synchronized (mSharedLock) {
             LocationTimeZoneProvider primary = createPrimaryProvider();
+            LocationTimeZoneProvider secondary = createSecondaryProvider();
             mLocationTimeZoneDetectorController =
-                    new ControllerImpl(mThreadingDomain, primary);
+                    new ControllerImpl(mThreadingDomain, primary, secondary);
             ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain);
             ControllerEnvironmentImpl environment = new ControllerEnvironmentImpl(
                     mThreadingDomain, mLocationTimeZoneDetectorController);
@@ -178,9 +182,6 @@
         if (isInSimulationMode(PRIMARY_PROVIDER_NAME)) {
             proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
         } else {
-            // TODO Uncomment this code in a later commit.
-            throw new UnsupportedOperationException("Not implemented");
-            /*
             proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
                     mContext,
                     mThreadingDomain,
@@ -188,11 +189,31 @@
                     com.android.internal.R.bool.config_enablePrimaryLocationTimeZoneOverlay,
                     com.android.internal.R.string.config_primaryLocationTimeZoneProviderPackageName
             );
-            */
         }
         return createLocationTimeZoneProvider(PRIMARY_PROVIDER_NAME, proxy);
     }
 
+    private LocationTimeZoneProvider createSecondaryProvider() {
+        LocationTimeZoneProviderProxy proxy;
+        if (isInSimulationMode(SECONDARY_PROVIDER_NAME)) {
+            proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
+        } else {
+            // TODO Uncomment this code in a later commit.
+            throw new UnsupportedOperationException("Not implemented");
+            /*
+            proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
+                    mContext,
+                    mThreadingDomain,
+                    SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
+                    com.android.internal.R.bool.config_enableSecondaryLocationTimeZoneOverlay,
+                    com.android.internal.R.string
+                            .config_secondaryLocationTimeZoneProviderPackageName
+            );
+            */
+        }
+        return createLocationTimeZoneProvider(SECONDARY_PROVIDER_NAME, proxy);
+    }
+
     private boolean isInSimulationMode(String providerName) {
         return SystemProperties.getBoolean(
                 SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX + providerName, false);
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
index ef2e349..f1d3723 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
@@ -21,6 +21,7 @@
 import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
 
 import static com.android.server.location.timezone.LocationTimeZoneManagerService.PRIMARY_PROVIDER_NAME;
+import static com.android.server.location.timezone.LocationTimeZoneManagerService.SECONDARY_PROVIDER_NAME;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -42,7 +43,8 @@
  */
 final class SimulatedBinderProviderEvent {
 
-    private static final List<String> VALID_PROVIDER_NAMES = Arrays.asList(PRIMARY_PROVIDER_NAME);
+    private static final List<String> VALID_PROVIDER_NAMES =
+            Arrays.asList(PRIMARY_PROVIDER_NAME, SECONDARY_PROVIDER_NAME);
 
     static final int INJECTED_EVENT_TYPE_ON_BIND = 1;
     static final int INJECTED_EVENT_TYPE_ON_UNBIND = 2;
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index a4a94c2..25ad9280 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -271,7 +271,7 @@
                 new Intent(ACTION_EVALUATE)
                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                         .putExtra(EXTRA_TIME, time),
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
         alarms.cancel(pendingIntent);
         if (time == 0 || time < now) {
             if (DEBUG) Slog.d(TAG, "Not scheduling evaluate: " + (time == 0 ? "no time specified"
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b4c98e0..98a2722 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5247,7 +5247,8 @@
                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
                 if (appIntent != null) {
                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
-                            getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
+                            getContext(), 0, appIntent, PendingIntent.FLAG_IMMUTABLE, null,
+                            UserHandle.of(userId));
                 }
                 final StatusBarNotification summarySbn =
                         new StatusBarNotification(adjustedSbn.getPackageName(),
@@ -6830,7 +6831,7 @@
                                     .appendPath(record.getKey()).build())
                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                             .putExtra(EXTRA_KEY, record.getKey()),
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
         }
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 961d3db..3517033 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -223,7 +223,7 @@
                 new Intent(ACTION_EVALUATE)
                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                         .putExtra(EXTRA_TIME, time),
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
         alarms.cancel(pendingIntent);
         if (time > now) {
             if (DEBUG) Slog.d(TAG, String.format("Scheduling evaluate for %s, in %s, now=%s",
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
new file mode 100644
index 0000000..dda5faf
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.IncrementalStatesInfo;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.incremental.IStorageHealthListener;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import java.util.function.BiConsumer;
+
+/**
+ * Manages state transitions of a package installed on Incremental File System. Currently manages:
+ * 1. startable state (whether a package is allowed to be launched), and
+ * 2. loading state (whether a package is still loading or has been fully loaded).
+ *
+ * The following events might change the states of a package:
+ * 1. Installation commit
+ * 2. Incremental storage health
+ * 3. Data loader stream health
+ * 4. Loading progress changes
+ *
+ * @hide
+ */
+public final class IncrementalStates {
+    private static final String TAG = "IncrementalStates";
+    private static final boolean DEBUG = false;
+    private final Handler mHandler = BackgroundThread.getHandler();
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private int mStreamStatus = IDataLoaderStatusListener.STREAM_HEALTHY;
+    @GuardedBy("mLock")
+    private int mStorageHealthStatus = IStorageHealthListener.HEALTH_STATUS_OK;
+    @GuardedBy("mLock")
+    private final LoadingState mLoadingState;
+    @GuardedBy("mLock")
+    private StartableState mStartableState;
+    @GuardedBy("mLock")
+    private Callback mCallback = null;
+    private final BiConsumer<Integer, Integer> mStatusConsumer;
+
+    public IncrementalStates() {
+        // By default the package is not startable and not fully loaded (i.e., is loading)
+        this(false, true);
+    }
+
+    public IncrementalStates(boolean isStartable, boolean isLoading) {
+        mStartableState = new StartableState(isStartable);
+        mLoadingState = new LoadingState(isLoading);
+        mStatusConsumer = new StatusConsumer();
+    }
+
+    /**
+     * Callback interface to report that the startable state of this package has changed.
+     */
+    public interface Callback {
+        /**
+         * Reports that the package is now unstartable and the unstartable reason.
+         */
+        void onPackageUnstartable(int reason);
+
+        /**
+         * Reports that the package is now startable.
+         */
+        void onPackageStartable();
+
+        /**
+         * Reports that package is fully loaded.
+         */
+        void onPackageFullyLoaded();
+    }
+
+    /**
+     * By calling this method, the caller indicates that package installation has just been
+     * committed. The package becomes startable. Set the initial loading state after the package
+     * is committed. Incremental packages are by-default loading; non-Incremental packages are not.
+     *
+     * @param isIncremental whether a package is installed on Incremental or not.
+     */
+    public void onCommit(boolean isIncremental) {
+        if (DEBUG) {
+            Slog.i(TAG, "received package commit event");
+        }
+        synchronized (mLock) {
+            if (!mStartableState.isStartable()) {
+                mStartableState.adoptNewStartableStateLocked(true);
+            }
+            if (mLoadingState.isLoading() != isIncremental) {
+                mLoadingState.adoptNewLoadingStateLocked(isIncremental);
+            }
+        }
+        mHandler.post(PooledLambda.obtainRunnable(
+                IncrementalStates::reportStartableState,
+                IncrementalStates.this).recycleOnUse());
+        if (!isIncremental) {
+            mHandler.post(PooledLambda.obtainRunnable(
+                    IncrementalStates::reportFullyLoaded,
+                    IncrementalStates.this).recycleOnUse());
+        }
+    }
+
+    private void reportStartableState() {
+        final Callback callback;
+        final boolean startable;
+        final int reason;
+        synchronized (mLock) {
+            callback = mCallback;
+            startable = mStartableState.isStartable();
+            reason = mStartableState.getUnstartableReason();
+        }
+        if (callback == null) {
+            return;
+        }
+        if (startable) {
+            callback.onPackageStartable();
+        } else {
+            callback.onPackageUnstartable(reason);
+        }
+    }
+
+    private void reportFullyLoaded() {
+        final Callback callback;
+        synchronized (mLock) {
+            callback = mCallback;
+        }
+        if (callback != null) {
+            callback.onPackageFullyLoaded();
+        }
+    }
+
+    private class StatusConsumer implements BiConsumer<Integer, Integer> {
+        @Override
+        public void accept(Integer streamStatus, Integer storageStatus) {
+            if (streamStatus == null && storageStatus == null) {
+                return;
+            }
+            final boolean oldState, newState;
+            synchronized (mLock) {
+                if (!mLoadingState.isLoading()) {
+                    // Do nothing if the package is already fully loaded
+                    return;
+                }
+                oldState = mStartableState.isStartable();
+                if (streamStatus != null) {
+                    mStreamStatus = (Integer) streamStatus;
+                }
+                if (storageStatus != null) {
+                    mStorageHealthStatus = (Integer) storageStatus;
+                }
+                updateStartableStateLocked();
+                newState = mStartableState.isStartable();
+            }
+            if (oldState != newState) {
+                mHandler.post(PooledLambda.obtainRunnable(IncrementalStates::reportStartableState,
+                        IncrementalStates.this).recycleOnUse());
+            }
+        }
+    };
+
+    /**
+     * By calling this method, the caller indicates that there issues with the Incremental
+     * Storage,
+     * on which the package is installed. The state will change according to the status
+     * code defined in {@code IStorageHealthListener}.
+     */
+    public void onStorageHealthStatusChanged(int storageHealthStatus) {
+        if (DEBUG) {
+            Slog.i(TAG, "received storage health status changed event : storageHealthStatus="
+                    + storageHealthStatus);
+        }
+        mStatusConsumer.accept(null, storageHealthStatus);
+    }
+
+    /**
+     * By calling this method, the caller indicates that the stream status of the package has
+     * been
+     * changed. This could indicate a streaming error. The state will change according to the
+     * status
+     * code defined in {@code IDataLoaderStatusListener}.
+     */
+    public void onStreamStatusChanged(int streamState) {
+        if (DEBUG) {
+            Slog.i(TAG, "received stream status changed event : streamState=" + streamState);
+        }
+        mStatusConsumer.accept(streamState, null);
+    }
+
+    /**
+     * Use the specified callback to report state changing events.
+     *
+     * @param callback Object to report new state.
+     */
+    public void setCallback(Callback callback) {
+        if (DEBUG) {
+            Slog.i(TAG, "registered callback");
+        }
+        synchronized (mLock) {
+            mCallback = callback;
+        }
+    }
+
+    /**
+     * Update the package loading progress to specified value. This might change startable state.
+     *
+     * @param progress Value between [0, 1].
+     */
+    public void setProgress(float progress) {
+        final boolean newLoadingState;
+        final boolean oldStartableState, newStartableState;
+        synchronized (mLock) {
+            oldStartableState = mStartableState.isStartable();
+            updateProgressLocked(progress);
+            newLoadingState = mLoadingState.isLoading();
+            newStartableState = mStartableState.isStartable();
+        }
+        if (!newLoadingState) {
+            mHandler.post(PooledLambda.obtainRunnable(
+                    IncrementalStates::reportFullyLoaded,
+                    IncrementalStates.this).recycleOnUse());
+        }
+        if (newStartableState != oldStartableState) {
+            mHandler.post(PooledLambda.obtainRunnable(
+                    IncrementalStates::reportStartableState,
+                    IncrementalStates.this).recycleOnUse());
+        }
+    }
+
+    /**
+     * @return the current startable state.
+     */
+    public boolean isStartable() {
+        synchronized (mLock) {
+            return mStartableState.isStartable();
+        }
+    }
+
+    /**
+     * @return Whether the package is still being loaded or has been fully loaded.
+     */
+    public boolean isLoading() {
+        synchronized (mLock) {
+            return mLoadingState.isLoading();
+        }
+    }
+
+    /**
+     * @return all current states in a Parcelable.
+     */
+    public IncrementalStatesInfo getIncrementalStatesInfo() {
+        synchronized (mLock) {
+            return new IncrementalStatesInfo(mStartableState.isStartable(),
+                    mLoadingState.isLoading(),
+                    mLoadingState.getProgress());
+        }
+    }
+
+    /**
+     * Determine the next state based on the current state, current stream status and storage
+     * health
+     * status. If the next state is different from the current state, proceed with state
+     * change.
+     */
+    private void updateStartableStateLocked() {
+        final boolean currentState = mStartableState.isStartable();
+        boolean nextState = currentState;
+        if (!currentState) {
+            if (mStorageHealthStatus == IStorageHealthListener.HEALTH_STATUS_OK
+                    && mStreamStatus == IDataLoaderStatusListener.STREAM_HEALTHY) {
+                // change from unstartable -> startable when both stream and storage are healthy
+                nextState = true;
+            }
+        } else {
+            if (mStorageHealthStatus == IStorageHealthListener.HEALTH_STATUS_UNHEALTHY) {
+                // unrecoverable if storage is unhealthy
+                nextState = false;
+            } else {
+                switch (mStreamStatus) {
+                    case IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR:
+                        // unrecoverable, fall through
+                    case IDataLoaderStatusListener.STREAM_SOURCE_ERROR: {
+                        // unrecoverable
+                        nextState = false;
+                        break;
+                    }
+                    case IDataLoaderStatusListener.STREAM_STORAGE_ERROR: {
+                        if (mStorageHealthStatus != IStorageHealthListener.HEALTH_STATUS_OK) {
+                            // unrecoverable if there is a pending read AND storage is limited
+                            nextState = false;
+                        }
+                        break;
+                    }
+                    default:
+                        // anything else, remain startable
+                        break;
+                }
+            }
+        }
+        if (nextState == currentState) {
+            return;
+        }
+        mStartableState.adoptNewStartableStateLocked(nextState);
+    }
+
+    private void updateProgressLocked(float progress) {
+        if (DEBUG) {
+            Slog.i(TAG, "received progress update: " + progress);
+        }
+        mLoadingState.setProgress(progress);
+        if (1 - progress < 0.001) {
+            if (DEBUG) {
+                Slog.i(TAG, "package is fully loaded");
+            }
+            mLoadingState.setProgress(1);
+            if (mLoadingState.isLoading()) {
+                mLoadingState.adoptNewLoadingStateLocked(false);
+            }
+            // Also updates startable state if necessary
+            if (!mStartableState.isStartable()) {
+                mStartableState.adoptNewStartableStateLocked(true);
+            }
+        }
+    }
+
+    private class StartableState {
+        private boolean mIsStartable;
+        private int mUnstartableReason = PackageManager.UNSTARTABLE_REASON_UNKNOWN;
+
+        StartableState(boolean isStartable) {
+            mIsStartable = isStartable;
+        }
+
+        public boolean isStartable() {
+            return mIsStartable;
+        }
+
+        public int getUnstartableReason() {
+            return mUnstartableReason;
+        }
+
+        public void adoptNewStartableStateLocked(boolean nextState) {
+            if (DEBUG) {
+                Slog.i(TAG, "startable state changed from " + mIsStartable + " to " + nextState);
+            }
+            mIsStartable = nextState;
+            mUnstartableReason = getUnstartableReasonLocked();
+        }
+
+        private int getUnstartableReasonLocked() {
+            if (mIsStartable) {
+                return PackageManager.UNSTARTABLE_REASON_UNKNOWN;
+            }
+            // Translate stream status to reason for unstartable state
+            switch (mStreamStatus) {
+                case IDataLoaderStatusListener.STREAM_TRANSPORT_ERROR:
+                    // fall through
+                case IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR:
+                    // fall through
+                case IDataLoaderStatusListener.STREAM_SOURCE_ERROR: {
+                    return PackageManager.UNSTARTABLE_REASON_DATALOADER_TRANSPORT;
+                }
+                case IDataLoaderStatusListener.STREAM_STORAGE_ERROR: {
+                    return PackageManager.UNSTARTABLE_REASON_DATALOADER_STORAGE;
+                }
+                default:
+                    return PackageManager.UNSTARTABLE_REASON_UNKNOWN;
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (!(o instanceof StartableState)) {
+                return false;
+            }
+            StartableState l = (StartableState) o;
+            return l.mIsStartable == mIsStartable;
+        }
+
+        @Override
+        public int hashCode() {
+            return Boolean.hashCode(mIsStartable);
+        }
+    }
+
+    private class LoadingState {
+        private boolean mIsLoading;
+        private float mProgress;
+
+        LoadingState(boolean isLoading) {
+            mIsLoading = isLoading;
+            mProgress = isLoading ? 0 : 1;
+        }
+
+        public boolean isLoading() {
+            return mIsLoading;
+        }
+
+        public float getProgress() {
+            return mProgress;
+        }
+
+        public void setProgress(float progress) {
+            mProgress = progress;
+        }
+
+        public void adoptNewLoadingStateLocked(boolean nextState) {
+            if (DEBUG) {
+                Slog.i(TAG, "Loading state changed from " + mIsLoading + " to " + nextState);
+            }
+            mIsLoading = nextState;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (!(o instanceof LoadingState)) {
+                return false;
+            }
+            LoadingState l = (LoadingState) o;
+            return l.mIsLoading == mIsLoading && l.mProgress == mProgress;
+        }
+
+        @Override
+        public int hashCode() {
+            int hashCode = Boolean.hashCode(mIsLoading);
+            hashCode = 31 * hashCode + Float.hashCode(mProgress);
+            return hashCode;
+        }
+    }
+
+
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof IncrementalStates)) {
+            return false;
+        }
+        IncrementalStates l = (IncrementalStates) o;
+        return l.mStorageHealthStatus == mStorageHealthStatus
+                && l.mStreamStatus == mStreamStatus
+                && l.mStartableState.equals(mStartableState)
+                && l.mLoadingState.equals(mLoadingState);
+    }
+
+    @Override
+    public int hashCode() {
+        int hashCode = mStartableState.hashCode();
+        hashCode = 31 * hashCode + mLoadingState.hashCode();
+        hashCode = 31 * hashCode + mStorageHealthStatus;
+        hashCode = 31 * hashCode + mStreamStatus;
+        return hashCode;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 9e6e1d9..2aafe9a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -141,6 +141,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexManager;
@@ -1700,20 +1701,26 @@
         }
     }
 
-    private void onStorageUnhealthy() {
+    private void onStorageHealthStatusChanged(int status) {
         final String packageName = getPackageName();
         if (TextUtils.isEmpty(packageName)) {
             // The package has not been installed.
             return;
         }
-        final PackageManagerService packageManagerService = mPm;
-        mHandler.post(() -> {
-            if (packageManagerService.deletePackageX(packageName,
-                    PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
-                    PackageManager.DELETE_ALL_USERS) != PackageManager.DELETE_SUCCEEDED) {
-                Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName);
-            }
-        });
+        mHandler.post(PooledLambda.obtainRunnable(
+                PackageManagerService::onStorageHealthStatusChanged,
+                mPm, packageName, status, userId).recycleOnUse());
+    }
+
+    private void onStreamHealthStatusChanged(int status) {
+        final String packageName = getPackageName();
+        if (TextUtils.isEmpty(packageName)) {
+            // The package has not been installed.
+            return;
+        }
+        mHandler.post(PooledLambda.obtainRunnable(
+                PackageManagerService::onStreamStatusChanged,
+                mPm, packageName, status, userId).recycleOnUse());
     }
 
     /**
@@ -3261,7 +3268,9 @@
                 if (isDestroyedOrDataLoaderFinished) {
                     switch (status) {
                         case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
-                            onStorageUnhealthy();
+                            // treat as unhealthy storage
+                            onStorageHealthStatusChanged(
+                                    IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
                             return;
                     }
                     return;
@@ -3358,6 +3367,16 @@
                     sendPendingStreaming(mContext, statusReceiver, sessionId, e.getMessage());
                 }
             }
+            @Override
+            public void reportStreamHealth(int dataLoaderId, int streamStatus) {
+                synchronized (mLock) {
+                    if (!mDestroyed && !mDataLoaderFinished) {
+                        // ignore streaming status if package isn't installed
+                        return;
+                    }
+                }
+                onStreamHealthStatusChanged(streamStatus);
+            }
         };
 
         if (!manualStartAndDestroy) {
@@ -3377,11 +3396,7 @@
                     }
                     if (isDestroyedOrDataLoaderFinished) {
                         // App's installed.
-                        switch (status) {
-                            case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
-                                onStorageUnhealthy();
-                                return;
-                        }
+                        onStorageHealthStatusChanged(status);
                         return;
                     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fb683d9..cc1ef86 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20,10 +20,8 @@
 import static android.Manifest.permission.INSTALL_PACKAGES;
 import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
 import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
-import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.MODE_IGNORED;
@@ -92,7 +90,6 @@
 import static android.content.pm.PackageManager.MOVE_FAILED_LOCKED_USER;
 import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
 import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.RESTRICTION_NONE;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
@@ -16392,12 +16389,24 @@
                 } else if (!previousUserIds.contains(userId)) {
                     ps.setInstallReason(installReason, userId);
                 }
+
+                // TODO(b/169721400): generalize Incremental States and create a Callback object
+                // that can be used for all the packages.
+                final IncrementalStatesCallback incrementalStatesCallback =
+                        new IncrementalStatesCallback(ps, userId);
+                final String codePath = ps.getPathString();
+                if (IncrementalManager.isIncrementalPath(codePath) && mIncrementalManager != null) {
+                    mIncrementalManager.registerCallback(codePath, incrementalStatesCallback);
+                    ps.setIncrementalStatesCallback(incrementalStatesCallback);
+                }
+
                 // Ensure that the uninstall reason is UNKNOWN for users with the package installed.
                 for (int currentUserId : allUsersList) {
                     if (ps.getInstalled(currentUserId)) {
                         ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);
                     }
                 }
+
                 mSettings.writeKernelMappingLPr(ps);
             }
             res.name = pkgName;
@@ -17194,6 +17203,7 @@
                 mDexManager.notifyPackageUpdated(pkg.getPackageName(),
                         pkg.getBaseApkPath(), pkg.getSplitCodePaths());
             }
+            reconciledPkg.pkgSetting.setStatesOnCommit();
 
             // Prepare the application profiles for the new code paths.
             // This needs to be done before invoking dexopt so that any install-time profile
@@ -17290,6 +17300,155 @@
         NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages);
     }
 
+    private class IncrementalStatesCallback extends IPackageLoadingProgressCallback.Stub
+            implements IncrementalStates.Callback {
+        @GuardedBy("mPackageSetting")
+        private final PackageSetting mPackageSetting;
+        private final String mPackageName;
+        private final String mPathString;
+        private final int mUserId;
+        private final int[] mInstalledUserIds;
+
+        IncrementalStatesCallback(PackageSetting packageSetting, int userId) {
+            mPackageSetting = packageSetting;
+            mPackageName = packageSetting.name;
+            mUserId = userId;
+            mPathString = packageSetting.getPathString();
+            final int[] allUserIds = resolveUserIds(userId);
+            final ArrayList<Integer> installedUserIds = new ArrayList<>();
+            for (int i = 0; i < allUserIds.length; i++) {
+                if (packageSetting.getInstalled(allUserIds[i])) {
+                    installedUserIds.add(allUserIds[i]);
+                }
+            }
+            final int numInstalledUserId = installedUserIds.size();
+            mInstalledUserIds = new int[numInstalledUserId];
+            for (int i = 0; i < numInstalledUserId; i++) {
+                mInstalledUserIds[i] = installedUserIds.get(i);
+            }
+        }
+
+        @Override
+        public void onPackageLoadingProgressChanged(float progress) {
+            synchronized (mPackageSetting) {
+                mPackageSetting.setLoadingProgress(progress);
+            }
+        }
+
+        @Override
+        public void onPackageFullyLoaded() {
+            mIncrementalManager.unregisterCallback(mPathString, this);
+            final SparseArray<int[]> newBroadcastAllowList;
+            synchronized (mLock) {
+                newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
+                        getPackageSettingInternal(mPackageName, Process.SYSTEM_UID),
+                        mInstalledUserIds, mSettings.mPackages);
+            }
+            Bundle extras = new Bundle(1);
+            extras.putInt(Intent.EXTRA_UID, mUserId);
+            extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
+            sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_LOADED, mPackageName,
+                    extras, 0 /*flags*/,
+                    null /*targetPackage*/, null /*finishedReceiver*/,
+                    mInstalledUserIds, null /* instantUserIds */, newBroadcastAllowList);
+        }
+
+        @Override
+        public void onPackageUnstartable(int reason) {
+            final SparseArray<int[]> newBroadcastAllowList;
+            synchronized (mLock) {
+                newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
+                        getPackageSettingInternal(mPackageName, Process.SYSTEM_UID),
+                        mInstalledUserIds, mSettings.mPackages);
+            }
+            Bundle extras = new Bundle(1);
+            extras.putInt(Intent.EXTRA_UID, mUserId);
+            extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
+            extras.putInt(Intent.EXTRA_REASON, reason);
+            // send broadcast to users with this app installed
+            sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTARTABLE, mPackageName,
+                    extras, 0 /*flags*/,
+                    null /*targetPackage*/, null /*finishedReceiver*/,
+                    mInstalledUserIds, null /* instantUserIds */, newBroadcastAllowList);
+        }
+
+        @Override
+        public void onPackageStartable() {
+            final SparseArray<int[]> newBroadcastAllowList;
+            synchronized (mLock) {
+                newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
+                        getPackageSettingInternal(mPackageName, Process.SYSTEM_UID),
+                        mInstalledUserIds, mSettings.mPackages);
+            }
+            Bundle extras = new Bundle(1);
+            extras.putInt(Intent.EXTRA_UID, mUserId);
+            extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
+            // send broadcast to users with this app installed
+            sendPackageBroadcast(Intent.ACTION_PACKAGE_STARTABLE, mPackageName,
+                    extras, 0 /*flags*/,
+                    null /*targetPackage*/, null /*finishedReceiver*/,
+                    mInstalledUserIds, null /* instantUserIds */, newBroadcastAllowList);
+        }
+    }
+
+    /**
+     * This is an internal method that is used to indicate changes on the health status of the
+     * Incremental Storage used by an installed package with an associated user id. This might
+     * result in a change in the loading state of the package.
+     */
+    public void onStorageHealthStatusChanged(String packageName, int status, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        mPermissionManager.enforceCrossUserPermission(
+                callingUid, userId, true, false,
+                "onStorageHealthStatusChanged");
+        final PackageSetting ps = getPackageSettingForUser(packageName, callingUid, userId);
+        if (ps == null) {
+            return;
+        }
+        ps.setStorageHealthStatus(status);
+    }
+
+    /**
+     * This is an internal method that is used to indicate changes on the stream status of the
+     * data loader used by an installed package with an associated user id. This might
+     * result in a change in the loading state of the package.
+     */
+    public void onStreamStatusChanged(String packageName, int status, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        mPermissionManager.enforceCrossUserPermission(
+                callingUid, userId, true, false,
+                "onStreamStatusChanged");
+        final PackageSetting ps = getPackageSettingForUser(packageName, callingUid, userId);
+        if (ps == null) {
+            return;
+        }
+        ps.setStreamStatus(status);
+    }
+
+    @Nullable PackageSetting getPackageSettingForUser(String packageName, int callingUid,
+            int userId) {
+        final PackageSetting ps;
+        synchronized (mLock) {
+            ps = mSettings.mPackages.get(packageName);
+            if (ps == null) {
+                Slog.w(TAG, "Failed to get package setting. Package " + packageName
+                        + " is not installed");
+                return null;
+            }
+            if (!ps.getInstalled(userId)) {
+                Slog.w(TAG, "Failed to get package setting. Package " + packageName
+                        + " is not installed for user " + userId);
+                return null;
+            }
+            if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                Slog.w(TAG, "Failed to get package setting. Package " + packageName
+                        + " is not visible to the calling app");
+                return null;
+            }
+        }
+        return ps;
+    }
+
     private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
       final PackageSetting pkgSetting = reconciledPkg.pkgSetting;
       final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.installResult;
@@ -21758,24 +21917,18 @@
 
         mInjector.getStorageManagerInternal().addExternalStoragePolicy(
                 new StorageManagerInternal.ExternalStorageMountPolicy() {
-            @Override
-            public int getMountMode(int uid, String packageName) {
-                if (Process.isIsolated(uid)) {
-                    return Zygote.MOUNT_EXTERNAL_NONE;
-                }
-                if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
-                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
-                }
-                if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
-                    return Zygote.MOUNT_EXTERNAL_READ;
-                }
-                return Zygote.MOUNT_EXTERNAL_WRITE;
-            }
+                    @Override
+                    public int getMountMode(int uid, String packageName) {
+                        if (Process.isIsolated(uid)) {
+                            return Zygote.MOUNT_EXTERNAL_NONE;
+                        }
+                        return Zygote.MOUNT_EXTERNAL_DEFAULT;
+                    }
 
-            @Override
-            public boolean hasExternalStorage(int uid, String packageName) {
-                return true;
-            }
+                    @Override
+                    public boolean hasExternalStorage(int uid, String packageName) {
+                        return true;
+                    }
         });
 
         // Now that we're mostly running, clean up stale users and apps
@@ -25409,24 +25562,15 @@
         @Override
         public boolean registerInstalledLoadingProgressCallback(String packageName,
                 PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            mPermissionManager.enforceCrossUserPermission(
-                    callingUid, userId, true, false,
-                    "registerLoadingProgressCallback");
-            final PackageSetting ps;
-            synchronized (mLock) {
-                ps = mSettings.mPackages.get(packageName);
-                if (ps == null) {
-                    Slog.w(TAG, "Failed registering loading progress callback. Package "
-                            + packageName + " is not installed");
-                    return false;
-                }
-                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                    Slog.w(TAG, "Failed registering loading progress callback. Package "
-                            + packageName + " is not visible to the calling app");
-                    return false;
-                }
-                // TODO(b/165841827): return false if package is fully loaded
+            final PackageSetting ps = getPackageSettingForUser(packageName, Binder.getCallingUid(),
+                    userId);
+            if (ps == null) {
+                return false;
+            }
+            if (!ps.isPackageLoading()) {
+                Slog.w(TAG,
+                        "Failed registering loading progress callback. Package is fully loaded.");
+                return false;
             }
             if (mIncrementalManager == null) {
                 Slog.w(TAG,
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 855a5ff5..2ff18f8 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -333,6 +333,8 @@
                     installSource.originatingPackageName);
             proto.end(sourceToken);
         }
+        proto.write(PackageProto.StatesProto.IS_STARTABLE, incrementalStates.isStartable());
+        proto.write(PackageProto.StatesProto.IS_LOADING, incrementalStates.isLoading());
         writeUsersInfoToProto(proto, PackageProto.USERS);
         proto.end(packageToken);
     }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index a7bbf8d..d52ad46 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -25,6 +25,7 @@
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IncrementalStatesInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.UninstallReason;
@@ -33,6 +34,7 @@
 import android.content.pm.Signature;
 import android.content.pm.SuspendDialogInfo;
 import android.os.PersistableBundle;
+import android.os.incremental.IncrementalManager;
 import android.service.pm.PackageProto;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -133,6 +135,9 @@
 
     boolean forceQueryableOverride;
 
+    @NonNull
+    public IncrementalStates incrementalStates;
+
     PackageSettingBase(String name, String realName, @NonNull File path,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
@@ -151,6 +156,7 @@
         this.versionCode = pVersionCode;
         this.signatures = new PackageSignatures();
         this.installSource = InstallSource.EMPTY;
+        this.incrementalStates = new IncrementalStates();
     }
 
     /**
@@ -257,6 +263,7 @@
                        orig.usesStaticLibrariesVersions.length) : null;
         updateAvailable = orig.updateAvailable;
         forceQueryableOverride = orig.forceQueryableOverride;
+        incrementalStates = orig.incrementalStates;
     }
 
     @VisibleForTesting
@@ -733,6 +740,66 @@
         modifyUserState(userId).resetOverrideComponentLabelIcon();
     }
 
+    /**
+     * @return True if package is startable, false otherwise.
+     */
+    public boolean isPackageStartable() {
+        return incrementalStates.isStartable();
+    }
+
+    /**
+     * @return True if package is still being loaded, false if the package is fully loaded.
+     */
+    public boolean isPackageLoading() {
+        return incrementalStates.isLoading();
+    }
+
+    /**
+     * @return all current states in a Parcelable.
+     */
+    public IncrementalStatesInfo getIncrementalStates() {
+        return incrementalStates.getIncrementalStatesInfo();
+    }
+
+    /**
+     * Called to indicate that the package installation has been committed. This will create a
+     * new startable state and a new loading state with default values. By default, the package is
+     * startable after commit. For a package installed on Incremental, the loading state is true.
+     * For non-Incremental packages, the loading state is false.
+     */
+    public void setStatesOnCommit() {
+        incrementalStates.onCommit(IncrementalManager.isIncrementalPath(getPathString()));
+    }
+
+    /**
+     * Called to set the callback to listen for startable state changes.
+     */
+    public void setIncrementalStatesCallback(IncrementalStates.Callback callback) {
+        incrementalStates.setCallback(callback);
+    }
+
+    /**
+     * Called to report progress changes. This might trigger loading state change.
+     * @see IncrementalStates#setProgress(float)
+     */
+    public void setLoadingProgress(float progress) {
+        incrementalStates.setProgress(progress);
+    }
+
+    /**
+     * @see IncrementalStates#onStorageHealthStatusChanged(int)
+     */
+    public void setStorageHealthStatus(int status) {
+        incrementalStates.onStorageHealthStatusChanged(status);
+    }
+
+    /**
+     * @see IncrementalStates#onStreamStatusChanged(int)
+     */
+    public void setStreamStatus(int status) {
+        incrementalStates.onStreamStatusChanged(status);
+    }
+
     protected PackageSettingBase updateFrom(PackageSettingBase other) {
         super.copyFrom(other);
         setPath(other.getPath());
@@ -756,6 +823,7 @@
         this.updateAvailable = other.updateAvailable;
         this.verificationInfo = other.verificationInfo;
         this.forceQueryableOverride = other.forceQueryableOverride;
+        this.incrementalStates = other.incrementalStates;
 
         if (mOldCodePaths != null) {
             if (other.mOldCodePaths != null) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a922d76..c16bd5c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2809,6 +2809,12 @@
         if (pkg.forceQueryableOverride) {
             serializer.attribute(null, "forceQueryable", "true");
         }
+        if (pkg.isPackageStartable()) {
+            serializer.attribute(null, "isStartable", "true");
+        }
+        if (pkg.isPackageLoading()) {
+            serializer.attribute(null, "isLoading", "true");
+        }
 
         writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
 
@@ -3594,6 +3600,8 @@
         String version = null;
         long versionCode = 0;
         String installedForceQueryable = null;
+        String isStartable = null;
+        String isLoading = null;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
@@ -3610,6 +3618,8 @@
             cpuAbiOverrideString = parser.getAttributeValue(null, "cpuAbiOverride");
             updateAvailable = parser.getAttributeValue(null, "updateAvailable");
             installedForceQueryable = parser.getAttributeValue(null, "forceQueryable");
+            isStartable = parser.getAttributeValue(null, "isStartable");
+            isLoading = parser.getAttributeValue(null, "isLoading");
 
             if (primaryCpuAbiString == null && legacyCpuAbiString != null) {
                 primaryCpuAbiString = legacyCpuAbiString;
@@ -3793,6 +3803,8 @@
             packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
             packageSetting.updateAvailable = "true".equals(updateAvailable);
             packageSetting.forceQueryableOverride = "true".equals(installedForceQueryable);
+            packageSetting.incrementalStates = new IncrementalStates("true".equals(isStartable),
+                    "true".equals(isLoading));
             // Handle legacy string here for single-user mode
             final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
             if (enabledStr != null) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index cfceaabf..7b044ed 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -77,6 +77,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.InputChannel;
@@ -709,8 +710,7 @@
             }
             sessionState.isCurrent = false;
             sessionState.currentChannel = null;
-            notifyCurrentChannelInfosUpdatedLocked(
-                    userState, getCurrentTvChannelInfosInternalLocked(userState));
+            notifyCurrentChannelInfosUpdatedLocked(userState);
         } catch (RemoteException | SessionNotFoundException e) {
             Slog.e(TAG, "error in releaseSession", e);
         } finally {
@@ -851,15 +851,18 @@
         }
     }
 
-    private void notifyCurrentChannelInfosUpdatedLocked(
-            UserState userState, List<TvChannelInfo> infos) {
+    private void notifyCurrentChannelInfosUpdatedLocked(UserState userState) {
         if (DEBUG) {
             Slog.d(TAG, "notifyCurrentChannelInfosUpdatedLocked");
         }
         int n = userState.mCallbacks.beginBroadcast();
         for (int i = 0; i < n; ++i) {
             try {
-                userState.mCallbacks.getBroadcastItem(i).onCurrentTvChannelInfosUpdated(infos);
+                ITvInputManagerCallback callback = userState.mCallbacks.getBroadcastItem(i);
+                Pair<Integer, Integer> pidUid = userState.callbackPidUidMap.get(callback);
+                List<TvChannelInfo> infos = getCurrentTvChannelInfosInternalLocked(
+                        userState, pidUid.first, pidUid.second);
+                callback.onCurrentTvChannelInfosUpdated(infos);
             } catch (RemoteException e) {
                 Slog.e(TAG, "failed to report updated current channel infos to callback", e);
             }
@@ -1063,14 +1066,19 @@
 
         @Override
         public void registerCallback(final ITvInputManagerCallback callback, int userId) {
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
-                    Binder.getCallingUid(), userId, "registerCallback");
+            int callingPid = Binder.getCallingPid();
+            int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "registerCallback");
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
                     final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                     if (!userState.mCallbacks.register(callback)) {
                         Slog.e(TAG, "client process has already died");
+                    } else {
+                        userState.callbackPidUidMap.put(
+                                callback, Pair.create(callingPid, callingUid));
                     }
                 }
             } finally {
@@ -1087,6 +1095,7 @@
                 synchronized (mLock) {
                     UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                     userState.mCallbacks.unregister(callback);
+                    userState.callbackPidUidMap.remove(callback);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -1419,8 +1428,8 @@
         @Override
         public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
             final int callingUid = Binder.getCallingUid();
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
-                    userId, "tune");
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId, "tune");
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -1432,8 +1441,7 @@
                         if (sessionState != null) {
                             sessionState.isCurrent = true;
                             sessionState.currentChannel = channelUri;
-                            notifyCurrentChannelInfosUpdatedLocked(
-                                    userState, getCurrentTvChannelInfosInternalLocked(userState));
+                            notifyCurrentChannelInfosUpdatedLocked(userState);
                         }
                         if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
                             // Do not log the watch history for passthrough inputs.
@@ -2090,16 +2098,13 @@
 
         @Override
         public List<TvChannelInfo> getCurrentTvChannelInfos(@UserIdInt int userId) {
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
-                    Binder.getCallingUid(), userId, "getTvCurrentChannelInfos");
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
-                    return getCurrentTvChannelInfosInternalLocked(userState);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+            int callingPid = Binder.getCallingPid();
+            int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "getTvCurrentChannelInfos");
+            synchronized (mLock) {
+                UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                return getCurrentTvChannelInfosInternalLocked(userState, callingPid, callingUid);
             }
         }
 
@@ -2273,14 +2278,15 @@
         }
     }
 
-    private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(UserState userState) {
+    private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(
+            UserState userState, int callingPid, int callingUid) {
         List<TvChannelInfo> channelInfos = new ArrayList<>();
-        boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission();
+        boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission(callingPid, callingUid);
         for (SessionState state : userState.sessionStateMap.values()) {
             if (state.isCurrent) {
                 Integer appTag;
                 int appType;
-                if (state.callingUid == Binder.getCallingUid()) {
+                if (state.callingUid == callingUid) {
                     appTag = APP_TAG_SELF;
                     appType = TvChannelInfo.APP_TYPE_SELF;
                 } else {
@@ -2322,8 +2328,8 @@
         return false;
     }
 
-    private boolean hasAccessWatchedProgramsPermission() {
-        return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS)
+    private boolean hasAccessWatchedProgramsPermission(int callingPid, int callingUid) {
+        return mContext.checkPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS, callingPid, callingUid)
                 == PackageManager.PERMISSION_GRANTED;
     }
 
@@ -2360,6 +2366,9 @@
         private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks =
                 new RemoteCallbackList<ITvInputManagerCallback>();
 
+        private final Map<ITvInputManagerCallback, Pair<Integer, Integer>> callbackPidUidMap =
+                new HashMap<>();
+
         // The token of a "main" TV input session.
         private IBinder mainSessionToken = null;
 
@@ -2712,8 +2721,7 @@
                 mSessionState.isCurrent = true;
                 mSessionState.currentChannel = channelUri;
                 UserState userState = getOrCreateUserStateLocked(mSessionState.userId);
-                notifyCurrentChannelInfosUpdatedLocked(
-                        userState, getCurrentTvChannelInfosInternalLocked(userState));
+                notifyCurrentChannelInfosUpdatedLocked(userState);
                 try {
                     // TODO: Consider adding this channel change in the watch log. When we do
                     // that, how we can protect the watch log from malicious tv inputs should
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b062b28..9868fc1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -116,6 +116,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -150,10 +151,7 @@
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
@@ -1133,16 +1131,14 @@
 
     boolean scheduleTopResumedActivityChanged(boolean onTop) {
         if (!attachedToProcess()) {
-            if (DEBUG_STATES) {
-                Slog.w(TAG, "Can't report activity position update - client not running"
-                                + ", activityRecord=" + this);
-            }
+            ProtoLog.w(WM_DEBUG_STATES,
+                    "Can't report activity position update - client not running, "
+                            + "activityRecord=%s", this);
             return false;
         }
         try {
-            if (DEBUG_STATES) {
-                Slog.v(TAG, "Sending position change to " + this + ", onTop: " + onTop);
-            }
+            ProtoLog.v(WM_DEBUG_STATES, "Sending position change to %s, onTop: %b",
+                    this, onTop);
 
             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     TopResumedActivityChangeItem.obtain(onTop));
@@ -2518,10 +2514,8 @@
      */
     @FinishRequest int finishIfPossible(int resultCode, Intent resultData,
             NeededUriGrants resultGrants, String reason, boolean oomAdj) {
-        if (DEBUG_RESULTS || DEBUG_STATES) {
-            Slog.v(TAG_STATES, "Finishing activity r=" + this + ", result=" + resultCode
-                    + ", data=" + resultData + ", reason=" + reason);
-        }
+        ProtoLog.v(WM_DEBUG_STATES, "Finishing activity r=%s, result=%d, data=%s, "
+                + "reason=%s", this, resultCode, resultData, reason);
 
         if (finishing) {
             Slog.w(TAG, "Duplicate finish request for r=" + this);
@@ -2603,7 +2597,7 @@
                 setVisibility(false);
 
                 if (stack.mPausingActivity == null) {
-                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + this);
+                    ProtoLog.v(WM_DEBUG_STATES, "Finish needs to pause: %s", this);
                     if (DEBUG_USER_LEAVING) {
                         Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false");
                     }
@@ -2650,7 +2644,7 @@
                 }
                 return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
             } else {
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + this);
+                ProtoLog.v(WM_DEBUG_STATES, "Finish waiting for pause of: %s", this);
             }
 
             return FINISH_RESULT_REQUESTED;
@@ -2807,7 +2801,7 @@
      */
     @VisibleForTesting
     boolean addToFinishingAndWaitForIdle() {
-        if (DEBUG_STATES) Slog.v(TAG, "Enqueueing pending finish: " + this);
+        ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending finish: %s", this);
         setState(FINISHING, "addToFinishingAndWaitForIdle");
         if (!mStackSupervisor.mFinishingActivities.contains(this)) {
             mStackSupervisor.mFinishingActivities.add(this);
@@ -2835,10 +2829,8 @@
         }
 
         if (isState(DESTROYING, DESTROYED)) {
-            if (DEBUG_STATES) {
-                Slog.v(TAG_STATES, "activity " + this + " already destroying."
-                        + "skipping request with reason:" + reason);
-            }
+            ProtoLog.v(WM_DEBUG_STATES, "activity %s already destroying, skipping "
+                    + "request with reason:%s", this, reason);
             return false;
         }
 
@@ -2879,16 +2871,13 @@
             // the list yet.  Otherwise, we can just immediately put it in the destroyed state since
             // we are not removing it from the list.
             if (finishing && !skipDestroy) {
-                if (DEBUG_STATES) {
-                    Slog.v(TAG_STATES, "Moving to DESTROYING: " + this + " (destroy requested)");
-                }
+                ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYING: %s (destroy requested)", this);
                 setState(DESTROYING,
                         "destroyActivityLocked. finishing and not skipping destroy");
                 mAtmService.mH.postDelayed(mDestroyTimeoutRunnable, DESTROY_TIMEOUT);
             } else {
-                if (DEBUG_STATES) {
-                    Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (destroy skipped)");
-                }
+                ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s "
+                        + "(destroy skipped)", this);
                 setState(DESTROYED,
                         "destroyActivityLocked. not finishing or skipping destroy");
                 if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + this);
@@ -2900,7 +2889,7 @@
                 removeFromHistory(reason + " hadNoApp");
                 removedFromHistory = true;
             } else {
-                if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (no app)");
+                ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s (no app)", this);
                 setState(DESTROYED, "destroyActivityLocked. not finishing and had no app");
             }
         }
@@ -2935,9 +2924,8 @@
 
         takeFromHistory();
         removeTimeouts();
-        if (DEBUG_STATES) {
-            Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (removed from history)");
-        }
+        ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s (removed from history)",
+                this);
         setState(DESTROYED, "removeFromHistory");
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
         detachFromProcess();
@@ -4455,12 +4443,12 @@
     }
 
     void setState(ActivityState state, String reason) {
-        if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
-                        + " to:" + state + " reason:" + reason);
+        ProtoLog.v(WM_DEBUG_STATES, "State movement: %s from:%s to:%s reason:%s",
+                this, getState(), state, reason);
 
         if (state == mState) {
             // No need to do anything if state doesn't change.
-            if (DEBUG_STATES) Slog.v(TAG_STATES, "State unchanged from:" + state);
+            ProtoLog.v(WM_DEBUG_STATES, "State unchanged from:%s", state);
             return;
         }
 
@@ -4943,7 +4931,7 @@
 
     static void activityResumedLocked(IBinder token) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-        if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
+        ProtoLog.i(WM_DEBUG_STATES, "Resumed activity; dropping state of: %s", r);
         if (r == null) {
             // If an app reports resumed after a long delay, the record on server side might have
             // been removed (e.g. destroy timeout), so the token could be null.
@@ -5014,8 +5002,8 @@
     }
 
     void activityPaused(boolean timeout) {
-        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
-                "Activity paused: token=" + appToken + ", timeout=" + timeout);
+        ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", appToken,
+                timeout);
 
         final Task stack = getStack();
 
@@ -5023,8 +5011,8 @@
             removePauseTimeout();
 
             if (stack.mPausingActivity == this) {
-                if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + this
-                        + (timeout ? " (due to timeout)" : " (pause complete)"));
+                ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,
+                        (timeout ? "(due to timeout)" : " (pause complete)"));
                 mAtmService.deferWindowLayout();
                 try {
                     stack.completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
@@ -5039,8 +5027,8 @@
                 if (isState(PAUSING)) {
                     setState(PAUSED, "activityPausedLocked");
                     if (finishing) {
-                        if (DEBUG_PAUSE) Slog.v(TAG,
-                                "Executing finish of failed to pause activity: " + this);
+                        ProtoLog.v(WM_DEBUG_STATES,
+                                "Executing finish of failed to pause activity: %s", this);
                         completeFinishing("activityPausedLocked");
                     }
                 }
@@ -5057,7 +5045,7 @@
     void schedulePauseTimeout() {
         pauseTime = SystemClock.uptimeMillis();
         mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT);
-        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
+        ProtoLog.v(WM_DEBUG_STATES, "Waiting for pause to complete...");
     }
 
     private void removePauseTimeout() {
@@ -5086,17 +5074,15 @@
         if (isNoHistory()) {
             if (!finishing) {
                 if (!stack.shouldSleepActivities()) {
-                    if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + this);
+                    ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s", this);
                     if (finishIfPossible("stop-no-history", false /* oomAdj */)
                             != FINISH_RESULT_CANCELLED) {
                         resumeKeyDispatchingLocked();
                         return;
                     }
                 } else {
-                    if (DEBUG_STATES) {
-                        Slog.d(TAG_STATES, "Not finishing noHistory " + this
-                                + " on stop because we're just sleeping");
-                    }
+                    ProtoLog.d(WM_DEBUG_STATES, "Not finishing noHistory %s on stop "
+                            + "because we're just sleeping", this);
                 }
             }
         }
@@ -5107,9 +5093,8 @@
         resumeKeyDispatchingLocked();
         try {
             stopped = false;
-            if (DEBUG_STATES) {
-                Slog.v(TAG_STATES, "Moving to STOPPING: " + this + " (stop requested)");
-            }
+            ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);
+
             setState(STOPPING, "stopIfPossible");
             if (DEBUG_VISIBILITY) {
                 Slog.v(TAG_VISIBILITY, "Stopping:" + this);
@@ -5129,7 +5114,7 @@
             Slog.w(TAG, "Exception thrown during pause", e);
             // Just in case, assume it to be stopped.
             stopped = true;
-            if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + this);
+            ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this);
             setState(STOPPED, "stopIfPossible");
             if (deferRelaunchUntilPaused) {
                 destroyImmediately("stop-except");
@@ -5158,9 +5143,9 @@
             launchCount = 0;
             updateTaskDescription(description);
         }
-        if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + mIcicle);
+        ProtoLog.i(WM_DEBUG_STATES, "Saving icicle of %s: %s", this, mIcicle);
         if (!stopped) {
-            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
+            ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPED: %s (stop complete)", this);
             removeStopTimeout();
             stopped = true;
             if (isStopping) {
@@ -5196,10 +5181,9 @@
         boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
                 || (isRootOfTask() && stack.getChildCount() <= 1);
         if (scheduleIdle || forceIdle) {
-            if (DEBUG_PAUSE) {
-                Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle=" + forceIdle
-                        + "immediate=" + !idleDelayed);
-            }
+            ProtoLog.v(WM_DEBUG_STATES,
+                    "Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed);
+
             if (!idleDelayed) {
                 mStackSupervisor.scheduleIdle();
             } else {
@@ -7126,9 +7110,9 @@
             } else {
                 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s",
                         this);
-                if (DEBUG_STATES && !mVisibleRequested) {
-                    Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
-                            + " called by " + Debug.getCallers(4));
+                if (!mVisibleRequested) {
+                    ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible "
+                            + "activity %s called by %s", this, Debug.getCallers(4));
                 }
                 relaunchActivityLocked(preserveWindow);
             }
@@ -7261,9 +7245,8 @@
         startFreezingScreenLocked(0);
 
         try {
-            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
-                    "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this
-                            + " callers=" + Debug.getCallers(6));
+            ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,
+                    (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
             forceNewConfig = false;
             startRelaunching();
             final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
@@ -7286,13 +7269,11 @@
             // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
         } catch (RemoteException e) {
-            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
+            ProtoLog.i(WM_DEBUG_STATES, "Relaunch failed %s", e);
         }
 
         if (andResume) {
-            if (DEBUG_STATES) {
-                Slog.d(TAG_STATES, "Resumed after relaunch " + this);
-            }
+            ProtoLog.d(WM_DEBUG_STATES, "Resumed after relaunch %s", this);
             results = null;
             newIntents = null;
             mAtmService.getAppWarningsLocked().onResumeActivity(this);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 3ef383b..e2c1303 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -44,15 +44,14 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IDLE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
@@ -66,7 +65,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
 import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
-import static com.android.server.wm.RootWindowContainer.TAG_STATES;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
 import static com.android.server.wm.Task.ActivityState.PAUSED;
@@ -135,6 +133,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.TransferPipe;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -721,9 +720,9 @@
             // While there are activities pausing we skipping starting any new activities until
             // pauses are complete. NOTE: that we also do this for activities that are starting in
             // the paused state because they will first be resumed then paused on the client side.
-            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
-                    "realStartActivityLocked: Skipping start of r=" + r
-                    + " some activities pausing...");
+            ProtoLog.v(WM_DEBUG_STATES,
+                    "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
+                    r);
             return false;
         }
 
@@ -919,8 +918,8 @@
             // This activity is not starting in the resumed state... which should look like we asked
             // it to pause+stop (but remain visible), and it has done so and reported back the
             // current icicle and other state.
-            if (DEBUG_STATES) Slog.v(TAG_STATES,
-                    "Moving to PAUSED: " + r + " (starting in paused state)");
+            ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s "
+                    + "(starting in paused state)", r);
             r.setState(PAUSED, "realStartActivityLocked");
             mRootWindowContainer.executeAppTransitionForAllDisplay();
         }
@@ -1071,11 +1070,11 @@
     /** Check if caller is allowed to launch activities on specified display. */
     boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId,
             ActivityInfo aInfo) {
-        if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: displayId=" + launchDisplayId
-                + " callingPid=" + callingPid + " callingUid=" + callingUid);
+        ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: displayId=%d callingPid=%d "
+                + "callingUid=%d", launchDisplayId, callingPid, callingUid);
 
         if (callingPid == -1 && callingUid == -1) {
-            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: no caller info, skip check");
+            ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: no caller info, skip check");
             return true;
         }
 
@@ -1091,8 +1090,7 @@
         final int startAnyPerm = mService.checkPermission(INTERNAL_SYSTEM_WINDOW, callingPid,
                 callingUid);
         if (startAnyPerm == PERMISSION_GRANTED) {
-            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
-                    + " allow launch any on display");
+            ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch any on display");
             return true;
         }
 
@@ -1104,36 +1102,36 @@
             // Limit launching on untrusted displays because their contents can be read from Surface
             // by apps that created them.
             if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
-                        + " disallow launch on virtual display for not-embedded activity.");
+                ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: disallow launch on "
+                        + "virtual display for not-embedded activity.");
                 return false;
             }
             // Check if the caller is allowed to embed activities from other apps.
             if (mService.checkPermission(ACTIVITY_EMBEDDING, callingPid, callingUid)
                     == PERMISSION_DENIED && !uidPresentOnDisplay) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
-                        + " disallow activity embedding without permission.");
+                ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: disallow activity "
+                        + "embedding without permission.");
                 return false;
             }
         }
 
         if (!displayContent.isPrivate()) {
             // Anyone can launch on a public display.
-            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
-                    + " allow launch on public display");
+            ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch on public "
+                    + "display");
             return true;
         }
 
         // Check if the caller is the owner of the display.
         if (display.getOwnerUid() == callingUid) {
-            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
-                    + " allow launch for owner of the display");
+            ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch for owner of the"
+                    + " display");
             return true;
         }
 
         if (uidPresentOnDisplay) {
-            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
-                    + " allow launch for caller present on the display");
+            ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: allow launch for caller "
+                    + "present on the display");
             return true;
         }
 
@@ -1832,8 +1830,8 @@
             final boolean animating = s.isAnimating(TRANSITION | PARENTS,
                     ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)
                     || mService.getTransitionController().inTransition(s);
-            if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + s.nowVisible
-                    + " animating=" + animating + " finishing=" + s.finishing);
+            ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
+                    + "finishing=%s", s, s.nowVisible, animating, s.finishing);
             if (!animating || mService.mShuttingDown) {
                 if (!processPausingActivities && s.isState(PAUSING)) {
                     // Defer processing pausing activities in this iteration and reschedule
@@ -1843,7 +1841,7 @@
                     continue;
                 }
 
-                if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
+                ProtoLog.v(WM_DEBUG_STATES, "Ready to stop: %s", s);
                 if (readyToStopActivities == null) {
                     readyToStopActivities = new ArrayList<>();
                 }
@@ -2077,7 +2075,7 @@
         msg.obj = r;
         r.topResumedStateLossTime = SystemClock.uptimeMillis();
         mHandler.sendMessageDelayed(msg, TOP_RESUMED_STATE_LOSS_TIMEOUT);
-        if (DEBUG_STATES) Slog.v(TAG_STATES, "Waiting for top state to be released by " + r);
+        ProtoLog.v(WM_DEBUG_STATES, "Waiting for top state to be released by %s", r);
     }
 
     /**
@@ -2085,10 +2083,9 @@
      * activity if needed.
      */
     void handleTopResumedStateReleased(boolean timeout) {
-        if (DEBUG_STATES) {
-            Slog.v(TAG_STATES, "Top resumed state released "
-                    + (timeout ? " (due to timeout)" : " (transition complete)"));
-        }
+        ProtoLog.v(WM_DEBUG_STATES, "Top resumed state released %s",
+                    (timeout ? "(due to timeout)" : "(transition complete)"));
+
         mHandler.removeMessages(TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG);
         if (!mTopResumedActivityWaitingForPrev) {
             // Top resumed activity state loss already handled.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index fa4373f..28e71fa 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -57,14 +57,13 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
@@ -1909,10 +1908,8 @@
             // if that is the case, so this is it!  And for paranoia, make sure we have
             // correctly resumed the top activity.
             if (!mMovedToFront && mDoResume) {
-                if (DEBUG_TASKS) {
-                    Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
-                            + " from " + targetTaskTop);
-                }
+                ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetStack,
+                        targetTaskTop);
                 mTargetStack.moveToFront("intentActivityFound");
             }
             resumeTargetStackIfNeeded();
@@ -2564,10 +2561,8 @@
                 mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
         addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
 
-        if (DEBUG_TASKS) {
-            Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
-                    + " in new task " + mStartActivity.getTask());
-        }
+        ProtoLog.v(WM_DEBUG_TASKS, "Starting new activity %s in new task %s",
+                mStartActivity, mStartActivity.getTask());
 
         if (taskToAffiliate != null) {
             mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
index 3c562a6..b5675a9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
@@ -43,14 +43,10 @@
     // Enable all debug log categories for activities.
     private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false;
 
-    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
     static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
     static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
-    static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_STACK = DEBUG_ALL || false;
-    static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
     public static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
-    static final boolean DEBUG_TASKS = DEBUG_ALL || false;
     static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
     static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
     static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c0e31f9..0938d22 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -70,6 +70,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
@@ -96,9 +97,7 @@
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
@@ -324,14 +323,14 @@
     /** Hardware-reported OpenGLES version. */
     final int GL_ES_VERSION;
 
-    public static final String DUMP_ACTIVITIES_CMD = "activities" ;
-    public static final String DUMP_ACTIVITIES_SHORT_CMD = "a" ;
-    public static final String DUMP_LASTANR_CMD = "lastanr" ;
-    public static final String DUMP_LASTANR_TRACES_CMD = "lastanr-traces" ;
-    public static final String DUMP_STARTER_CMD = "starter" ;
-    public static final String DUMP_CONTAINERS_CMD = "containers" ;
-    public static final String DUMP_RECENTS_CMD = "recents" ;
-    public static final String DUMP_RECENTS_SHORT_CMD = "r" ;
+    public static final String DUMP_ACTIVITIES_CMD = "activities";
+    public static final String DUMP_ACTIVITIES_SHORT_CMD = "a";
+    public static final String DUMP_LASTANR_CMD = "lastanr";
+    public static final String DUMP_LASTANR_TRACES_CMD = "lastanr-traces";
+    public static final String DUMP_STARTER_CMD = "starter";
+    public static final String DUMP_CONTAINERS_CMD = "containers";
+    public static final String DUMP_RECENTS_CMD = "recents";
+    public static final String DUMP_RECENTS_SHORT_CMD = "r";
 
     /** This activity is not being relaunched, or being relaunched for a non-resize reason. */
     public static final int RELAUNCH_REASON_NONE = 0;
@@ -614,7 +613,9 @@
             LAYOUT_REASON_CONFIG_CHANGED,
             LAYOUT_REASON_VISIBILITY_CHANGED,
     })
-    @interface LayoutReason {}
+    @interface LayoutReason {
+    }
+
     static final int LAYOUT_REASON_CONFIG_CHANGED = 0x1;
     static final int LAYOUT_REASON_VISIBILITY_CHANGED = 0x2;
 
@@ -653,7 +654,8 @@
      *
      * @see #updateResumedAppTrace
      */
-    private @Nullable ActivityRecord mTracedResumedActivity;
+    @Nullable
+    private ActivityRecord mTracedResumedActivity;
 
     /** If non-null, we are tracking the time the user spends in the currently focused app. */
     AppTimeTracker mCurAppTimeTracker;
@@ -716,6 +718,7 @@
         int OOM_ADJUSTMENT = 1;
         int LRU_UPDATE = 2;
         int PROCESS_CHANGE = 3;
+
         int caller() default NONE;
     }
 
@@ -873,7 +876,8 @@
     }
 
     protected ActivityStackSupervisor createStackSupervisor() {
-        final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mH.getLooper());
+        final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this,
+                mH.getLooper());
         supervisor.initialize();
         return supervisor;
     }
@@ -1128,7 +1132,7 @@
             throw new IllegalArgumentException("Bad PendingIntent object");
         }
 
-        PendingIntentRecord pir = (PendingIntentRecord)target;
+        PendingIntentRecord pir = (PendingIntentRecord) target;
 
         synchronized (mGlobalLock) {
             // If this is coming from the currently resumed activity, it is
@@ -1181,14 +1185,14 @@
 
                 // Look for the original activity in the list...
                 final int N = resolves != null ? resolves.size() : 0;
-                for (int i=0; i<N; i++) {
+                for (int i = 0; i < N; i++) {
                     ResolveInfo rInfo = resolves.get(i);
                     if (rInfo.activityInfo.packageName.equals(r.packageName)
                             && rInfo.activityInfo.name.equals(r.info.name)) {
                         // We found the current one...  the next matching is
                         // after it.
                         i++;
-                        if (i<N) {
+                        if (i < N) {
                             aInfo = resolves.get(i).activityInfo;
                         }
                         if (debug) {
@@ -1212,11 +1216,10 @@
 
             intent.setComponent(new ComponentName(
                     aInfo.applicationInfo.packageName, aInfo.name));
-            intent.setFlags(intent.getFlags()&~(
-                    Intent.FLAG_ACTIVITY_FORWARD_RESULT|
-                            Intent.FLAG_ACTIVITY_CLEAR_TOP|
-                            Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
-                            FLAG_ACTIVITY_NEW_TASK));
+            intent.setFlags(intent.getFlags() & ~(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP
+                    | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+                    | FLAG_ACTIVITY_NEW_TASK));
 
             // Okay now we need to start the new activity, replacing the currently running activity.
             // This is a little tricky because we want to start the new one as if the current one is
@@ -1581,11 +1584,12 @@
     /**
      * Start the recents activity to perform the recents animation.
      *
-     * @param intent The intent to start the recents activity.
+     * @param intent                 The intent to start the recents activity.
+     * @param eventTime              When the (touch) event is triggered to start recents activity.
      * @param recentsAnimationRunner Pass {@code null} to only preload the activity.
      */
     @Override
-    public void startRecentsActivity(Intent intent, @Deprecated IAssistDataReceiver unused,
+    public void startRecentsActivity(Intent intent, long eventTime,
             @Nullable IRecentsAnimationRunner recentsAnimationRunner) {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
         final int callingPid = Binder.getCallingPid();
@@ -1605,7 +1609,7 @@
                 if (recentsAnimationRunner == null) {
                     anim.preloadRecentsActivity();
                 } else {
-                    anim.startRecentsActivity(recentsAnimationRunner);
+                    anim.startRecentsActivity(recentsAnimationRunner, eventTime);
                 }
             }
         } finally {
@@ -1637,12 +1641,12 @@
      *
      * If the target display is private or virtual, some restrictions will apply.
      *
-     * @param displayId Target display id.
-     * @param intent Intent used to launch the activity.
+     * @param displayId    Target display id.
+     * @param intent       Intent used to launch the activity.
      * @param resolvedType The MIME type of the intent.
-     * @param userId The id of the user for whom the call is made.
+     * @param userId       The id of the user for whom the call is made.
      * @return {@code true} if a call to start an activity on the target display should succeed and
-     *         no {@link SecurityException} will be thrown, {@code false} otherwise.
+     * no {@link SecurityException} will be thrown, {@code false} otherwise.
      */
     @Override
     public final boolean isActivityStartAllowedOnDisplay(int displayId, Intent intent,
@@ -1671,11 +1675,10 @@
     /**
      * This is the internal entry point for handling Activity.finish().
      *
-     * @param token The Binder token referencing the Activity we want to finish.
+     * @param token      The Binder token referencing the Activity we want to finish.
      * @param resultCode Result code, if any, from this Activity.
      * @param resultData Result data (Intent), if any, from this Activity.
      * @param finishTask Whether to finish the task associated with this Activity.
-     *
      * @return Returns true if the activity successfully finished, or false if it is still running.
      */
     @Override
@@ -2310,14 +2313,14 @@
      * There are several possible results of this call:
      * - if the task is locked, then we will show the lock toast
      * - if there is a task behind the provided task, then that task is made visible and resumed as
-     *   this task is moved to the back
+     * this task is moved to the back
      * - otherwise, if there are no other tasks in the stack:
-     *     - if this task is in the pinned stack, then we remove the stack completely, which will
-     *       have the effect of moving the task to the top or bottom of the fullscreen stack
-     *       (depending on whether it is visible)
-     *     - otherwise, we simply return home and hide this task
+     * - if this task is in the pinned stack, then we remove the stack completely, which will
+     * have the effect of moving the task to the top or bottom of the fullscreen stack
+     * (depending on whether it is visible)
+     * - otherwise, we simply return home and hide this task
      *
-     * @param token A reference to the activity we wish to move
+     * @param token   A reference to the activity we wish to move
      * @param nonRoot If false then this only works if the activity is the root
      *                of a task; if true it will work for any activity in a task.
      * @return Returns true if the move completed, false if not.
@@ -2398,8 +2401,8 @@
                     return false;
                 }
 
-                if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId
-                        + " to windowingMode=" + windowingMode + " toTop=" + toTop);
+                ProtoLog.d(WM_DEBUG_TASKS, "setTaskWindowingMode: moving task=%d "
+                        + "to windowingMode=%d toTop=%b", taskId, windowingMode, toTop);
 
                 if (!task.isActivityTypeStandardOrUndefined()) {
                     throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
@@ -2462,7 +2465,8 @@
 
     @Override
     public void unhandledBack() {
-        mAmInternal.enforceCallingPermission(android.Manifest.permission.FORCE_BACK, "unhandledBack()");
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
+                "unhandledBack()");
 
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
@@ -2509,9 +2513,10 @@
     @Override
     public void moveTaskToFront(IApplicationThread appThread, String callingPackage, int taskId,
             int flags, Bundle bOptions) {
-        mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
+                "moveTaskToFront()");
 
-        if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
+        ProtoLog.d(WM_DEBUG_TASKS, "moveTaskToFront: moving taskId=%d", taskId);
         synchronized (mGlobalLock) {
             moveTaskToFrontLocked(appThread, callingPackage, taskId, flags,
                     SafeActivityOptions.fromBundle(bOptions));
@@ -2543,7 +2548,7 @@
         try {
             final Task task = mRootWindowContainer.anyTaskForId(taskId);
             if (task == null) {
-                Slog.d(TAG, "Could not find task for id: "+ taskId);
+                ProtoLog.d(WM_DEBUG_TASKS, "Could not find task for id: %d", taskId);
                 SafeActivityOptions.abort(options);
                 return;
             }
@@ -2756,8 +2761,8 @@
                     return;
                 }
 
-                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
-                        + " to stackId=" + stackId + " toTop=" + toTop);
+                ProtoLog.d(WM_DEBUG_TASKS, "moveTaskToStack: moving task=%d to "
+                        + "stackId=%d toTop=%b", taskId, stackId, toTop);
 
                 final Task stack = mRootWindowContainer.getStack(stackId);
                 if (stack == null) {
@@ -2780,7 +2785,7 @@
      * Moves the specified task to the primary-split-screen stack.
      *
      * @param taskId Id of task to move.
-     * @param toTop If the task and stack should be moved to the top.
+     * @param toTop  If the task and stack should be moved to the top.
      * @return Whether the task was successfully put into splitscreen.
      */
     @Override
@@ -3293,8 +3298,8 @@
                 if (intent.getSourceBounds() != null) {
                     intent.setSourceBounds(null);
                 }
-                if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) {
-                    if ((intent.getFlags()&Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) == 0) {
+                if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) {
+                    if ((intent.getFlags() & Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) == 0) {
                         // The caller has added this as an auto-remove task...  that makes no
                         // sense, so turn off auto-remove.
                         intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
@@ -3492,8 +3497,8 @@
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
-                        + " to displayId=" + displayId);
+                ProtoLog.d(WM_DEBUG_TASKS, "moveStackToDisplay: moving stackId=%d to "
+                        + "displayId=%d", stackId, displayId);
                 mRootWindowContainer.moveStackToDisplay(stackId, displayId, ON_TOP);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -3652,14 +3657,16 @@
                 try {
                     if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
                         allowed = true;
-                        if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
-                                + " is using old GET_TASKS but privileged; allowing");
+                        ProtoLog.w(WM_DEBUG_TASKS,
+                                "%s: caller %d is using old GET_TASKS but privileged; allowing",
+                                caller, callingUid);
                     }
                 } catch (RemoteException e) {
                 }
             }
-            if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
-                    + " does not hold REAL_GET_TASKS; limiting output");
+            ProtoLog.w(WM_DEBUG_TASKS,
+                    "%s: caller %d does not hold REAL_GET_TASKS; limiting output", caller,
+                    callingUid);
         }
         return allowed;
     }
@@ -3978,7 +3985,8 @@
 
     @Override
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
-        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
+                "suppressResizeConfigChanges()");
         synchronized (mGlobalLock) {
             mSuppressResizeConfigChanges = suppress;
         }
@@ -3988,10 +3996,9 @@
      * Moves the top activity in the input stackId to the pinned stack.
      *
      * @param stackId Id of stack to move the top activity to pinned stack.
-     * @param bounds Bounds to use for pinned stack.
-     *
+     * @param bounds  Bounds to use for pinned stack.
      * @return True if the top activity of the input stack was successfully moved to the pinned
-     *          stack.
+     * stack.
      */
     @Override
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
@@ -4146,7 +4153,7 @@
 
         if (params.hasSetAspectRatio()
                 && !mWindowManager.isValidPictureInPictureAspectRatio(
-                        r.mDisplayContent, params.getAspectRatio())) {
+                r.mDisplayContent, params.getAspectRatio())) {
             final float minAspectRatio = mContext.getResources().getFloat(
                     com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
             final float maxAspectRatio = mContext.getResources().getFloat(
@@ -4194,8 +4201,8 @@
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
                 final Rect primaryRect =
                         tempDockedTaskInsetBounds != null ? tempDockedTaskInsetBounds
-                            : (tempDockedTaskBounds != null ? tempDockedTaskBounds
-                                    : dockedBounds);
+                                : (tempDockedTaskBounds != null ? tempDockedTaskBounds
+                                        : dockedBounds);
                 wct.setBounds(primary.mRemoteToken.toWindowContainerToken(), primaryRect);
                 Rect otherRect = tempOtherTaskInsetBounds != null ? tempOtherTaskInsetBounds
                         : tempOtherTaskBounds;
@@ -4464,7 +4471,8 @@
     public void updateLockTaskFeatures(int userId, int flags) {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != SYSTEM_UID) {
-            mAmInternal.enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+            mAmInternal.enforceCallingPermission(
+                    android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
                     "updateLockTaskFeatures()");
         }
         synchronized (mGlobalLock) {
@@ -4768,11 +4776,12 @@
 
     /**
      * Clears launch params for the given package.
+     *
      * @param packageNames the names of the packages of which the launch params are to be cleared
      */
     @Override
     public void clearLaunchParamsForPackages(List<String> packageNames) {
-        mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
                 "clearLaunchParamsForPackages");
         synchronized (mGlobalLock) {
             for (int i = 0; i < packageNames.size(); ++i) {
@@ -4787,7 +4796,7 @@
      */
     @Override
     public void setDisplayToSingleTaskInstance(int displayId) {
-        mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
                 "setDisplayToSingleTaskInstance");
         final long origId = Binder.clearCallingIdentity();
         try {
@@ -4806,7 +4815,7 @@
      */
     @Override
     public void requestPictureInPictureMode(IBinder token) throws RemoteException {
-        mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
                 "requestPictureInPictureMode");
         final long origId = Binder.clearCallingIdentity();
         try {
@@ -4902,7 +4911,7 @@
         boolean needSep = printedAnything;
 
         boolean printed = ActivityStackSupervisor.printThisActivity(pw,
-                mRootWindowContainer.getTopResumedActivity(),  dumpPackage, needSep,
+                mRootWindowContainer.getTopResumedActivity(), dumpPackage, needSep,
                 "  ResumedActivity: ", null);
         if (printed) {
             printedAnything = true;
@@ -4936,19 +4945,20 @@
 
     /**
      * There are three things that cmd can be:
-     *  - a flattened component name that matches an existing activity
-     *  - the cmd arg isn't the flattened component name of an existing activity:
-     *    dump all activity whose component contains the cmd as a substring
-     *  - A hex number of the ActivityRecord object instance.
+     * - a flattened component name that matches an existing activity
+     * - the cmd arg isn't the flattened component name of an existing activity:
+     * dump all activity whose component contains the cmd as a substring
+     * - A hex number of the ActivityRecord object instance.
      * <p>
      * The caller should not hold lock when calling this method because it will wait for the
      * activities to complete the dump.
      *
-     *  @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
-     *  @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
+     * @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
+     * @param dumpFocusedStackOnly  dump activity with {@param name} only if in the focused stack
      */
     protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
-            int opti, boolean dumpAll, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) {
+            int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
+            boolean dumpFocusedStackOnly) {
         ArrayList<ActivityRecord> activities;
 
         synchronized (mGlobalLock) {
@@ -4975,9 +4985,12 @@
                 final Task task = r.getTask();
                 if (lastTask != task) {
                     lastTask = task;
-                    pw.print("TASK "); pw.print(lastTask.affinity);
-                    pw.print(" id="); pw.print(lastTask.mTaskId);
-                    pw.print(" userId="); pw.println(lastTask.mUserId);
+                    pw.print("TASK ");
+                    pw.print(lastTask.affinity);
+                    pw.print(" id=");
+                    pw.print(lastTask.mTaskId);
+                    pw.print(" userId=");
+                    pw.println(lastTask.mUserId);
                     if (dumpAll) {
                         lastTask.dump(pw, "  ");
                     }
@@ -4997,8 +5010,11 @@
         String innerPrefix = prefix + "  ";
         IApplicationThread appThread = null;
         synchronized (mGlobalLock) {
-            pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
-            pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
+            pw.print(prefix);
+            pw.print("ACTIVITY ");
+            pw.print(r.shortComponentName);
+            pw.print(" ");
+            pw.print(Integer.toHexString(System.identityHashCode(r)));
             pw.print(" pid=");
             if (r.hasProcess()) {
                 pw.println(r.app.getPid());
@@ -5057,7 +5073,7 @@
 
     public Configuration getConfiguration() {
         Configuration ci;
-        synchronized(mGlobalLock) {
+        synchronized (mGlobalLock) {
             ci = new Configuration(getGlobalConfigurationForCallingPid());
             ci.userSetLocale = false;
         }
@@ -5902,7 +5918,7 @@
 
         final IBinder threadBinder = thread.asBinder();
         final ArrayMap<String, SparseArray<WindowProcessController>> pmap = mProcessNames.getMap();
-        for (int i = pmap.size()-1; i >= 0; i--) {
+        for (int i = pmap.size() - 1; i >= 0; i--) {
             final SparseArray<WindowProcessController> procs = pmap.valueAt(i);
             for (int j = procs.size() - 1; j >= 0; j--) {
                 final WindowProcessController proc = procs.valueAt(j);
@@ -5967,7 +5983,7 @@
                         TimeMigrationUtils.formatMillisWithFixedFormat(System.currentTimeMillis());
                 sb.append(timeString);
                 sb.append(": ");
-                TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
+                TimeUtils.formatDuration(SystemClock.uptimeMillis() - startTime, sb);
                 sb.append(" since ");
                 sb.append(msg);
                 FileOutputStream fos = new FileOutputStream(tracesFile);
@@ -5990,7 +6006,7 @@
 
             File lastTracesFile = null;
             File curTracesFile = null;
-            for (int i=9; i>=0; i--) {
+            for (int i = 9; i >= 0; i--) {
                 String name = String.format(Locale.US, "slow%02d.txt", i);
                 curTracesFile = new File(tracesDir, name);
                 if (curTracesFile.exists()) {
@@ -6037,7 +6053,8 @@
                 case REPORT_TIME_TRACKER_MSG: {
                     AppTimeTracker tracker = (AppTimeTracker) msg.obj;
                     tracker.deliverResult(mContext);
-                } break;
+                }
+                break;
             }
         }
     }
@@ -6233,7 +6250,7 @@
          */
         @Override
         public void setVr2dDisplayId(int vr2dDisplayId) {
-            if (DEBUG_STACK) Slog.d(TAG, "setVr2dDisplayId called for: " + vr2dDisplayId);
+            ProtoLog.d(WM_DEBUG_TASKS, "setVr2dDisplayId called for: %d", vr2dDisplayId);
             synchronized (mGlobalLock) {
                 mVr2dDisplayId = vr2dDisplayId;
             }
@@ -6541,7 +6558,7 @@
          * Set the corresponding display information for the process global configuration. To be
          * called when we need to show IME on a different display.
          *
-         * @param pid The process id associated with the IME window.
+         * @param pid       The process id associated with the IME window.
          * @param displayId The ID of the display showing the IME.
          */
         @Override
@@ -6553,7 +6570,7 @@
 
             if (pid == MY_PID || pid < 0) {
                 ProtoLog.w(WM_DEBUG_CONFIGURATION,
-                            "Trying to update display configuration for system/invalid process.");
+                        "Trying to update display configuration for system/invalid process.");
                 return;
             }
             synchronized (mGlobalLock) {
@@ -6943,7 +6960,8 @@
                 pw.println();
                 getActivityStartController().dump(pw, "  ", null);
                 pw.println();
-                pw.println("-------------------------------------------------------------------------------");
+                pw.println("-------------------------------------------------------------------"
+                        + "------------");
                 dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
                         true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
                         "" /* header */);
diff --git a/services/core/java/com/android/server/wm/DisplayAreaGroup.java b/services/core/java/com/android/server/wm/DisplayAreaGroup.java
new file mode 100644
index 0000000..bcf8c7c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayAreaGroup.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.reverseOrientation;
+
+import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
+
+/** The root of a partition of the logical display. */
+class DisplayAreaGroup extends RootDisplayArea {
+
+    DisplayAreaGroup(WindowManagerService wms, String name, int featureId) {
+        super(wms, name, featureId);
+    }
+
+    @Override
+    boolean isOrientationDifferentFromDisplay() {
+        if (mDisplayContent == null) {
+            return false;
+        }
+
+        final Rect bounds = getBounds();
+        final Rect displayBounds = mDisplayContent.getBounds();
+
+        return (bounds.width() < bounds.height())
+                != (displayBounds.width() < displayBounds.height());
+    }
+
+    @ActivityInfo.ScreenOrientation
+    @Override
+    int getOrientation(int candidate) {
+        int orientation = super.getOrientation(candidate);
+
+        // Reverse the requested orientation if the orientation of this DAG is different from the
+        // display, so that when the display rotates to the reversed orientation, this DAG will be
+        // in the requested orientation, so as the requested app.
+        // For example, if the display is 1200x900 (landscape), and this DAG is 600x900 (portrait).
+        // When an app below this DAG is requesting landscape, it should actually request the
+        // display to be portrait, so that the DAG and the app will be in landscape.
+        return isOrientationDifferentFromDisplay() ? reverseOrientation(orientation) : orientation;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 255b3f1..d292580 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -35,10 +35,10 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.os.Process.SYSTEM_UID;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -72,6 +72,7 @@
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.am.ActivityManagerService;
 
@@ -157,7 +158,8 @@
      */
     private int mRecentsUid = -1;
     private ComponentName mRecentsComponent = null;
-    private @Nullable String mFeatureId;
+    @Nullable
+    private String mFeatureId;
 
     /**
      * Mapping of user id -> whether recent tasks have been loaded for that user.
@@ -397,7 +399,7 @@
 
     /**
      * @return whether the given component is the recents component and shares the same uid as the
-     *         recents component.
+     * recents component.
      */
     boolean isRecentsComponent(ComponentName cn, int uid) {
         return cn.equals(mRecentsComponent) && UserHandle.isSameApp(uid, mRecentsUid);
@@ -423,7 +425,8 @@
     /**
      * @return the featureId for the recents component.
      */
-    @Nullable String getRecentsComponentFeatureId() {
+    @Nullable
+    String getRecentsComponentFeatureId() {
         return mFeatureId;
     }
 
@@ -617,7 +620,7 @@
 
     /** Remove recent tasks for a user. */
     private void removeTasksForUserLocked(int userId) {
-        if(userId <= 0) {
+        if (userId <= 0) {
             Slog.i(TAG, "Can't remove recent task on user " + userId);
             return;
         }
@@ -625,8 +628,8 @@
         for (int i = mTasks.size() - 1; i >= 0; --i) {
             Task task = mTasks.get(i);
             if (task.mUserId == userId) {
-                if(DEBUG_TASKS) Slog.i(TAG_TASKS,
-                        "remove RecentTask " + task + " when finishing user" + userId);
+                ProtoLog.i(WM_DEBUG_TASKS, "remove RecentTask %s when finishing user "
+                        + "%d", task, userId);
                 remove(task);
             }
         }
@@ -640,11 +643,11 @@
                     && packageNames.contains(task.realActivity.getPackageName())
                     && task.mUserId == userId
                     && task.realActivitySuspended != suspended) {
-               task.realActivitySuspended = suspended;
-               if (suspended) {
-                   mSupervisor.removeTask(task, false, REMOVE_FROM_RECENTS, "suspended-package");
-               }
-               notifyTaskPersisterLocked(task, false);
+                task.realActivitySuspended = suspended;
+                if (suspended) {
+                    mSupervisor.removeTask(task, false, REMOVE_FROM_RECENTS, "suspended-package");
+                }
+                notifyTaskPersisterLocked(task, false);
             }
         }
     }
@@ -780,25 +783,31 @@
                         continue;
                     } else {
                         // Otherwise just not available for now.
-                        if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
-                                "Making recent unavailable: " + task);
+                        if (DEBUG_RECENTS && task.isAvailable) {
+                            Slog.d(TAG_RECENTS,
+                                    "Making recent unavailable: " + task);
+                        }
                         task.isAvailable = false;
                     }
                 } else {
                     if (!ai.enabled || !ai.applicationInfo.enabled
                             || (ai.applicationInfo.flags
-                                    & ApplicationInfo.FLAG_INSTALLED) == 0) {
-                        if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
-                                "Making recent unavailable: " + task
-                                        + " (enabled=" + ai.enabled + "/"
-                                        + ai.applicationInfo.enabled
-                                        + " flags="
-                                        + Integer.toHexString(ai.applicationInfo.flags)
-                                        + ")");
+                            & ApplicationInfo.FLAG_INSTALLED) == 0) {
+                        if (DEBUG_RECENTS && task.isAvailable) {
+                            Slog.d(TAG_RECENTS,
+                                    "Making recent unavailable: " + task
+                                            + " (enabled=" + ai.enabled + "/"
+                                            + ai.applicationInfo.enabled
+                                            + " flags="
+                                            + Integer.toHexString(ai.applicationInfo.flags)
+                                            + ")");
+                        }
                         task.isAvailable = false;
                     } else {
-                        if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
-                                "Making recent available: " + task);
+                        if (DEBUG_RECENTS && !task.isAvailable) {
+                            Slog.d(TAG_RECENTS,
+                                    "Making recent available: " + task);
+                        }
                         task.isAvailable = true;
                     }
                 }
@@ -974,16 +983,20 @@
         final int size = mTasks.size();
         for (int i = 0; i < size; i++) {
             final Task task = mTasks.get(i);
-            if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task
-                    + " persistable=" + task.isPersistable);
+            if (TaskPersister.DEBUG) {
+                Slog.d(TAG, "LazyTaskWriter: task=" + task
+                        + " persistable=" + task.isPersistable);
+            }
             final Task rootTask = task.getRootTask();
             if ((task.isPersistable || task.inRecents)
                     && (rootTask == null || !rootTask.isHomeOrRecentsStack())) {
                 if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
                 persistentTaskIds.add(task.mTaskId);
             } else {
-                if (TaskPersister.DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task="
-                        + task);
+                if (TaskPersister.DEBUG) {
+                    Slog.d(TAG, "omitting from persistentTaskIds task="
+                            + task);
+                }
             }
         }
     }
@@ -1051,8 +1064,10 @@
         // TODO: VI what about if it's just an activity?
         // Probably nothing to do here
         if (task.voiceSession != null) {
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                    "addRecent: not adding voice interaction " + task);
+            if (DEBUG_RECENTS) {
+                Slog.d(TAG_RECENTS,
+                        "addRecent: not adding voice interaction " + task);
+            }
             return;
         }
         // Another quick case: check if the top-most recent task is the same.
@@ -1064,8 +1079,10 @@
         // tasks that are at the top.
         if (isAffiliated && recentsCount > 0 && task.inRecents
                 && task.mAffiliatedTaskId == mTasks.get(0).mAffiliatedTaskId) {
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0)
-                    + " at top when adding " + task);
+            if (DEBUG_RECENTS) {
+                Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0)
+                        + " at top when adding " + task);
+            }
             return;
         }
 
@@ -1122,14 +1139,17 @@
                     if (other == task.mNextAffiliate) {
                         // We found the index of our next affiliation, which is who is
                         // before us in the list, so add after that point.
-                        taskIndex = otherIndex+1;
+                        taskIndex = otherIndex + 1;
                     } else {
                         // We found the index of our previous affiliation, which is who is
                         // after us in the list, so add at their position.
                         taskIndex = otherIndex;
                     }
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                            "addRecent: new affiliated task added at " + taskIndex + ": " + task);
+                    if (DEBUG_RECENTS) {
+                        Slog.d(TAG_RECENTS,
+                                "addRecent: new affiliated task added at " + taskIndex + ": "
+                                        + task);
+                    }
                     mTasks.add(taskIndex, task);
                     notifyTaskAdded(task);
 
@@ -1143,13 +1163,17 @@
                     // everything and then go through our general path of adding a new task.
                     needAffiliationFix = true;
                 } else {
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                            "addRecent: couldn't find other affiliation " + other);
+                    if (DEBUG_RECENTS) {
+                        Slog.d(TAG_RECENTS,
+                                "addRecent: couldn't find other affiliation " + other);
+                    }
                     needAffiliationFix = true;
                 }
             } else {
-                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                        "addRecent: adding affiliated task without next/prev:" + task);
+                if (DEBUG_RECENTS) {
+                    Slog.d(TAG_RECENTS,
+                            "addRecent: adding affiliated task without next/prev:" + task);
+                }
                 needAffiliationFix = true;
             }
         }
@@ -1204,8 +1228,10 @@
             final Task task = mTasks.remove(recentsCount - 1);
             notifyTaskRemoved(task, true /* wasTrimmed */, false /* killProcess */);
             recentsCount--;
-            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + task
-                    + " max=" + mGlobalMaxNumTasks);
+            if (DEBUG_RECENTS_TRIM_TASKS) {
+                Slog.d(TAG, "Trimming over max-recents task=" + task
+                        + " max=" + mGlobalMaxNumTasks);
+            }
         }
 
         // Remove any tasks that belong to currently quiet profiles
@@ -1216,13 +1242,15 @@
             if (userInfo != null && userInfo.isManagedProfile() && userInfo.isQuietModeEnabled()) {
                 mTmpQuietProfileUserIds.put(userId, true);
             }
-            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "User: " + userInfo
-                    + " quiet=" + mTmpQuietProfileUserIds.get(userId));
+            if (DEBUG_RECENTS_TRIM_TASKS) {
+                Slog.d(TAG, "User: " + userInfo
+                        + " quiet=" + mTmpQuietProfileUserIds.get(userId));
+            }
         }
 
         // Remove any inactive tasks, calculate the latest set of visible tasks.
         int numVisibleTasks = 0;
-        for (int i = 0; i < mTasks.size();) {
+        for (int i = 0; i < mTasks.size(); ) {
             final Task task = mTasks.get(i);
 
             if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) {
@@ -1246,8 +1274,10 @@
                     } else {
                         // Fall through to trim visible tasks that are no longer in range and
                         // trimmable
-                        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
-                                "Trimming out-of-range visible task=" + task);
+                        if (DEBUG_RECENTS_TRIM_TASKS) {
+                            Slog.d(TAG,
+                                    "Trimming out-of-range visible task=" + task);
+                        }
                     }
                 }
             } else {
@@ -1266,8 +1296,10 @@
      * @return whether the given task should be considered active.
      */
     private boolean isActiveRecentTask(Task task, SparseBooleanArray quietProfileUserIds) {
-        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task
-                + " globalMax=" + mGlobalMaxNumTasks);
+        if (DEBUG_RECENTS_TRIM_TASKS) {
+            Slog.d(TAG, "isActiveRecentTask: task=" + task
+                    + " globalMax=" + mGlobalMaxNumTasks);
+        }
 
         if (quietProfileUserIds.get(task.mUserId)) {
             // Quiet profile user's tasks are never active
@@ -1280,8 +1312,10 @@
             final Task affiliatedTask = getTask(task.mAffiliatedTaskId);
             if (affiliatedTask != null) {
                 if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) {
-                    if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
-                            "\taffiliatedWithTask=" + affiliatedTask + " is not active");
+                    if (DEBUG_RECENTS_TRIM_TASKS) {
+                        Slog.d(TAG,
+                                "\taffiliatedWithTask=" + affiliatedTask + " is not active");
+                    }
                     return false;
                 }
             }
@@ -1296,13 +1330,15 @@
      */
     @VisibleForTesting
     boolean isVisibleRecentTask(Task task) {
-        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task
-                + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
-                + " sessionDuration=" + mActiveTasksSessionDurationMs
-                + " inactiveDuration=" + task.getInactiveDuration()
-                + " activityType=" + task.getActivityType()
-                + " windowingMode=" + task.getWindowingMode()
-                + " intentFlags=" + task.getBaseIntent().getFlags());
+        if (DEBUG_RECENTS_TRIM_TASKS) {
+            Slog.d(TAG, "isVisibleRecentTask: task=" + task
+                    + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
+                    + " sessionDuration=" + mActiveTasksSessionDurationMs
+                    + " inactiveDuration=" + task.getInactiveDuration()
+                    + " activityType=" + task.getActivityType()
+                    + " windowingMode=" + task.getWindowingMode()
+                    + " intentFlags=" + task.getBaseIntent().getFlags());
+        }
 
         switch (task.getActivityType()) {
             case ACTIVITY_TYPE_HOME:
@@ -1468,8 +1504,10 @@
                 mHiddenTasks.add(removedTask);
             }
             notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
-            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
-                    + " for addition of task=" + task);
+            if (DEBUG_RECENTS_TRIM_TASKS) {
+                Slog.d(TAG, "Trimming task=" + removedTask
+                        + " for addition of task=" + task);
+            }
         }
         notifyTaskPersisterLocked(removedTask, false /* flush */);
     }
@@ -1622,16 +1660,20 @@
             top = top.mNextAffiliate;
             topIndex--;
         }
-        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at "
-                + topIndex + " from intial " + taskIndex);
+        if (DEBUG_RECENTS) {
+            Slog.d(TAG_RECENTS, "addRecent: adding affiliates starting at "
+                    + topIndex + " from initial " + taskIndex);
+        }
         // Find the end of the chain, doing a validity check along the way.
         boolean isValid = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
         int endIndex = topIndex;
         Task prev = top;
         while (endIndex < recentsCount) {
             Task cur = mTasks.get(endIndex);
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
-                    + endIndex + " " + cur);
+            if (DEBUG_RECENTS) {
+                Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
+                        + endIndex + " " + cur);
+            }
             if (cur == top) {
                 // Verify start of the chain.
                 if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) {
@@ -1701,14 +1743,18 @@
         if (isValid) {
             // All looks good, we can just move all of the affiliated tasks
             // to the top.
-            for (int i=topIndex; i<=endIndex; i++) {
-                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
-                        + " from " + i + " to " + (i-topIndex));
+            for (int i = topIndex; i <= endIndex; i++) {
+                if (DEBUG_RECENTS) {
+                    Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
+                            + " from " + i + " to " + (i - topIndex));
+                }
                 Task cur = mTasks.remove(i);
                 mTasks.add(i - topIndex, cur);
             }
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks  " +  topIndex
-                    + " to " + endIndex);
+            if (DEBUG_RECENTS) {
+                Slog.d(TAG_RECENTS, "addRecent: done moving tasks  " + topIndex
+                        + " to " + endIndex);
+            }
             return true;
         }
 
@@ -1768,7 +1814,9 @@
                 printedHeader = true;
                 printedAnything = true;
             }
-            pw.print("  * Recent #"); pw.print(i); pw.print(": ");
+            pw.print("  * Recent #");
+            pw.print(i);
+            pw.print(": ");
             pw.println(task);
             if (dumpAll) {
                 task.dump(pw, "    ");
@@ -1787,7 +1835,7 @@
                     boolean match = taskInfo.baseIntent != null
                             && taskInfo.baseIntent.getComponent() != null
                             && dumpPackage.equals(
-                                    taskInfo.baseIntent.getComponent().getPackageName());
+                            taskInfo.baseIntent.getComponent().getPackageName());
                     if (!match) {
                         match |= taskInfo.baseActivity != null
                                 && dumpPackage.equals(taskInfo.baseActivity.getPackageName());
@@ -1818,7 +1866,9 @@
                     printedAnything = true;
                 }
 
-                pw.print("  * RecentTaskInfo #"); pw.print(i); pw.print(": ");
+                pw.print("  * RecentTaskInfo #");
+                pw.print(i);
+                pw.print(": ");
                 taskInfo.dump(pw, "    ");
             }
         }
@@ -1842,8 +1892,8 @@
 
     /**
      * @return Whether the activity types and windowing modes of the two tasks are considered
-     *         compatible. This is necessary because we currently don't persist the activity type
-     *         or the windowing mode with the task, so they can be undefined when restored.
+     * compatible. This is necessary because we currently don't persist the activity type
+     * or the windowing mode with the task, so they can be undefined when restored.
      */
     private boolean hasCompatibleActivityTypeAndWindowingMode(Task t1, Task t2) {
         final int activityType = t1.getActivityType();
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 35338bb..1cf50ab 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -161,7 +161,7 @@
         }
     }
 
-    void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner) {
+    void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner, long eventTime) {
         ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "startRecentsActivity(): intent=%s", mTargetIntent);
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RecentsAnimation#startRecentsActivity");
 
@@ -249,8 +249,13 @@
             // we fetch the visible tasks to be controlled by the animation
             mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
 
+            ActivityOptions options = null;
+            if (eventTime > 0) {
+                options = ActivityOptions.makeBasic();
+                options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
+            }
             mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
-                    START_TASK_TO_FRONT, targetActivity, null /* options */);
+                    START_TASK_TO_FRONT, targetActivity, options);
 
             // Register for stack order changes
             mDefaultTaskDisplayArea.registerStackOrderChangedListener(this);
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index c3953b4..9181a0f 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -17,14 +17,12 @@
 package com.android.server.wm;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.Task.TAG_TASKS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 
 import android.app.ActivityOptions;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.Debug;
-import android.util.Slog;
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.function.pooled.PooledConsumer;
@@ -201,8 +199,8 @@
 
             noOptions = takeOption(p, noOptions);
 
-            if (DEBUG_TASKS) Slog.w(TAG_TASKS,
-                    "resetTaskIntendedTask: calling finishActivity on " + p);
+            ProtoLog.w(WM_DEBUG_TASKS, "resetTaskIntendedTask: calling finishActivity "
+                    + "on %s", p);
             p.finishIfPossible(reason, false /* oomAdj */);
         }
     }
@@ -213,15 +211,15 @@
 
         while (!mResultActivities.isEmpty()) {
             final ActivityRecord p = mResultActivities.remove(0);
-            if (ignoreFinishing&& p.finishing) continue;
+            if (ignoreFinishing && p.finishing) continue;
 
             if (takeOptions) {
                 noOptions = takeOption(p, noOptions);
             }
             ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from task=%s "
-                    + "adding to task=%s Callers=%s", p, mTask,  targetTask, Debug.getCallers(4));
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS,
-                    "Pushing next activity " + p + " out to target's task " + target);
+                    + "adding to task=%s Callers=%s", p, mTask, targetTask, Debug.getCallers(4));
+            ProtoLog.v(WM_DEBUG_TASKS, "Pushing next activity %s out to target's task %s", p,
+                    target);
             p.reparent(targetTask, position, "resetTargetTaskIfNeeded");
         }
     }
@@ -253,8 +251,8 @@
                 // If the activity currently at the bottom has the same task affinity as
                 // the one we are moving, then merge it into the same task.
                 targetTask = task;
-                if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
-                        + r + " out to bottom task " + targetTask);
+                ProtoLog.v(WM_DEBUG_TASKS, "Start pushing activity %s out to bottom task %s", r,
+                        targetTask);
             }
             if (targetTask == null) {
                 if (alwaysCreateTask) {
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index faed7fa..d9a8773 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -27,7 +27,8 @@
 
 /**
  * Root of a {@link DisplayArea} hierarchy. It can be either the {@link DisplayContent} as the root
- * of the whole logical display, or the root of a {@link DisplayArea} group.
+ * of the whole logical display, or a {@link DisplayAreaGroup} as the root of a partition of the
+ * logical display.
  */
 class RootDisplayArea extends DisplayArea<DisplayArea> {
 
@@ -50,6 +51,16 @@
         super(wms, Type.ANY, name, featureId);
     }
 
+    @Override
+    RootDisplayArea getRootDisplayArea() {
+        return this;
+    }
+
+    /** Whether the orientation (based on dimensions) of this root is different from the Display. */
+    boolean isOrientationDifferentFromDisplay() {
+        return false;
+    }
+
     /** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
     DisplayArea.Tokens findAreaForToken(WindowToken token) {
         int windowLayerFromType = token.getWindowLayerFromType();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2df56a3..cabf1bf 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -44,6 +44,8 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
@@ -55,11 +57,8 @@
 import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
@@ -179,7 +178,6 @@
     private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1;
     private static final int SET_USER_ACTIVITY_TIMEOUT = 2;
     static final String TAG_TASKS = TAG + POSTFIX_TASKS;
-    private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
     static final String TAG_STATES = TAG + POSTFIX_STATES;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
 
@@ -235,7 +233,9 @@
             MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
             MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
     })
-    public @interface AnyTaskForIdMatchTaskMode {}
+    public @interface AnyTaskForIdMatchTaskMode {
+    }
+
     // Match only tasks in the current stacks
     static final int MATCH_TASK_IN_STACKS_ONLY = 0;
     // Match either tasks in the current stacks, or in the recent tasks if not found in the stacks
@@ -305,6 +305,7 @@
     };
 
     private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
+
     static class FindTaskResult implements Function<Task, Boolean> {
         ActivityRecord mRecord;
         boolean mIdealMatch;
@@ -335,7 +336,8 @@
             // If documentData is non-null then it must match the existing task data.
             documentData = isDocument ? intent.getData() : null;
 
-            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + parent);
+            ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s in %s", target,
+                    parent);
             parent.forAllLeafTasks(this);
         }
 
@@ -353,12 +355,12 @@
         public Boolean apply(Task task) {
             if (task.voiceSession != null) {
                 // We never match voice sessions; those always run independently.
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
+                ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: voice session", task);
                 return false;
             }
             if (task.mUserId != userId) {
                 // Looking for a different task.
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
+                ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: different user", task);
                 return false;
             }
 
@@ -366,11 +368,11 @@
             final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
             if (r == null || r.finishing || r.mUserId != userId
                     || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
+                ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r);
                 return false;
             }
             if (!r.hasCompatibleActivityType(mTarget)) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
+                ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch activity type", task);
                 return false;
             }
 
@@ -389,40 +391,40 @@
                 taskDocumentData = null;
             }
 
-            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
-                    + (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
-                    + "/aff=" + r.getTask().rootAffinity + " to new cls="
-                    + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
+            ProtoLog.d(WM_DEBUG_TASKS, "Comparing existing cls=%s /aff=%s to new cls=%s /aff=%s",
+                    r.getTask().rootAffinity, intent.getComponent().flattenToShortString(),
+                    info.taskAffinity, (task.realActivity != null
+                            ? task.realActivity.flattenToShortString() : ""));
             // TODO Refactor to remove duplications. Check if logic can be simplified.
             if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
                     && Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
+                ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
                 //dump();
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
-                        "For Intent " + intent + " bringing to top: " + r.intent);
+                ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
                 mRecord = r;
                 mIdealMatch = true;
                 return true;
             } else if (affinityIntent != null && affinityIntent.getComponent() != null
                     && affinityIntent.getComponent().compareTo(cls) == 0 &&
                     Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
-                        "For Intent " + intent + " bringing to top: " + r.intent);
+                ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
+                ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
                 mRecord = r;
                 mIdealMatch = true;
                 return true;
             } else if (!isDocument && !taskIsDocument
                     && mRecord == null && task.rootAffinity != null) {
                 if (task.rootAffinity.equals(mTarget.taskAffinity)) {
-                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
+                    ProtoLog.d(WM_DEBUG_TASKS, "Found matching affinity candidate!");
                     // It is possible for multiple tasks to have the same root affinity especially
                     // if they are in separate stacks. We save off this candidate, but keep looking
                     // to see if there is a better candidate.
                     mRecord = r;
                     mIdealMatch = false;
                 }
-            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
+            } else {
+                ProtoLog.d(WM_DEBUG_TASKS, "Not a match: %s", task);
+            }
 
             return false;
         }
@@ -578,6 +580,7 @@
      * Returns {@code true} if the callingUid has any non-toast window currently visible to the
      * user. Also ignores {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_STARTING},
      * since those windows don't belong to apps.
+     *
      * @see WindowState#isNonToastOrStarting()
      */
     boolean isAnyNonToastWindowVisibleForUid(int callingUid) {
@@ -791,7 +794,7 @@
                         "Looks like we have reclaimed some memory, clearing surface for retry.");
                 if (surfaceController != null) {
                     ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
-                            "SURFACE RECOVER DESTROY: %s",  winAnimator.mWin);
+                            "SURFACE RECOVER DESTROY: %s", winAnimator.mWin);
                     winAnimator.destroySurface();
                     if (winAnimator.mWin.mActivityRecord != null) {
                         winAnimator.mWin.mActivityRecord.removeStartingWindow();
@@ -822,8 +825,10 @@
     // "Something has changed!  Let's make it correct now."
     // TODO: Super long method that should be broken down...
     void performSurfacePlacementNoTrace() {
-        if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
-                + Debug.getCallers(3));
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
+                    + Debug.getCallers(3));
+        }
 
         int i;
 
@@ -851,8 +856,10 @@
         final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
         final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
 
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+        if (SHOW_LIGHT_TRANSACTIONS) {
+            Slog.i(TAG,
+                    ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+        }
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
         mWmService.openSurfaceTransaction();
         try {
@@ -862,8 +869,10 @@
         } finally {
             mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
+            if (SHOW_LIGHT_TRANSACTIONS) {
+                Slog.i(TAG,
+                        "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
+            }
         }
         mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
 
@@ -896,8 +905,10 @@
 
         if (isLayoutNeeded()) {
             defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("mLayoutNeeded",
-                    defaultDisplay.pendingLayoutChanges);
+            if (DEBUG_LAYOUT_REPEATS) {
+                surfacePlacer.debugLayoutRepeats("mLayoutNeeded",
+                        defaultDisplay.pendingLayoutChanges);
+            }
         }
 
         handleResizingWindows();
@@ -1105,11 +1116,11 @@
     }
 
     /**
-     * @param w WindowState this method is applied to.
+     * @param w        WindowState this method is applied to.
      * @param obscured True if there is a window on top of this obscuring the display.
-     * @param syswin System window?
+     * @param syswin   System window?
      * @return True when the display contains content to show the user. When false, the display
-     *          manager may choose to mirror or blank the display.
+     * manager may choose to mirror or blank the display.
      */
     boolean handleNotObscuredLocked(WindowState w, boolean obscured, boolean syswin) {
         final WindowManager.LayoutParams attrs = w.mAttrs;
@@ -1243,7 +1254,8 @@
     }
 
     void dumpTopFocusedDisplayId(PrintWriter pw) {
-        pw.print("  mTopFocusedDisplayId="); pw.println(mTopFocusedDisplayId);
+        pw.print("  mTopFocusedDisplayId=");
+        pw.println(mTopFocusedDisplayId);
     }
 
     void dumpLayoutNeededDisplayIds(PrintWriter pw) {
@@ -1359,7 +1371,8 @@
         }
     }
 
-    @Nullable Context getDisplayUiContext(int displayId) {
+    @Nullable
+    Context getDisplayUiContext(int displayId) {
         return getDisplayContent(displayId) != null
                 ? getDisplayContent(displayId).getDisplayUiContext() : null;
     }
@@ -1437,7 +1450,8 @@
      * corresponding record in display manager.
      */
     // TODO: Look into consolidating with getDisplayContent()
-    @Nullable DisplayContent getDisplayContentOrCreate(int displayId) {
+    @Nullable
+    DisplayContent getDisplayContentOrCreate(int displayId) {
         DisplayContent displayContent = getDisplayContent(displayId);
         if (displayContent != null) {
             return displayContent;
@@ -1494,8 +1508,8 @@
 
         final DisplayContent display = getDisplayContent(displayId);
         return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
-                result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
-                        allowInstrumenting, fromHomeKey),
+                        result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
+                                allowInstrumenting, fromHomeKey),
                 false /* initValue */);
     }
 
@@ -1504,11 +1518,11 @@
      * displayId - default display area always uses primary home component.
      * For secondary display areas, the home activity must have category SECONDARY_HOME and then
      * resolves according to the priorities listed below.
-     *  - If default home is not set, always use the secondary home defined in the config.
-     *  - Use currently selected primary home activity.
-     *  - Use the activity in the same package as currently selected primary home activity.
-     *    If there are multiple activities matched, use first one.
-     *  - Use the secondary home defined in the config.
+     * - If default home is not set, always use the secondary home defined in the config.
+     * - Use currently selected primary home activity.
+     * - Use the activity in the same package as currently selected primary home activity.
+     * If there are multiple activities matched, use first one.
+     * - Use the secondary home defined in the config.
      */
     boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
             boolean allowInstrumenting, boolean fromHomeKey) {
@@ -1556,6 +1570,7 @@
 
     /**
      * This resolves the home activity info.
+     *
      * @return the home activity info if any.
      */
     @VisibleForTesting
@@ -1629,7 +1644,8 @@
         }
 
         if (aInfo != null) {
-            if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, false /* allowInstrumenting */)) {
+            if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea,
+                    false /* allowInstrumenting */)) {
                 aInfo = null;
             }
         }
@@ -1687,6 +1703,7 @@
 
     /**
      * Check if the display area is valid for secondary home activity.
+     *
      * @param taskDisplayArea The target display area.
      * @return {@code true} if allow to launch, {@code false} otherwise.
      */
@@ -1727,8 +1744,10 @@
 
     /**
      * Check if home activity start should be allowed on a display.
-     * @param homeInfo {@code ActivityInfo} of the home activity that is going to be launched.
-     * @param taskDisplayArea The target display area.
+     *
+     * @param homeInfo           {@code ActivityInfo} of the home activity that is going to be
+     *                           launched.
+     * @param taskDisplayArea    The target display area.
      * @param allowInstrumenting Whether launching home should be allowed if being instrumented.
      * @return {@code true} if allow to launch, {@code false} otherwise.
      */
@@ -1773,13 +1792,14 @@
     /**
      * Ensure all activities visibility, update orientation and configuration.
      *
-     * @param starting The currently starting activity or {@code null} if there is none.
-     * @param displayId The id of the display where operation is executed.
+     * @param starting                  The currently starting activity or {@code null} if there is
+     *                                  none.
+     * @param displayId                 The id of the display where operation is executed.
      * @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to
      *                                  {@code true} if config changed.
-     * @param deferResume Whether to defer resume while updating config.
+     * @param deferResume               Whether to defer resume while updating config.
      * @return 'true' if starting activity was kept or wasn't provided, 'false' if it was relaunched
-     *         because of configuration update.
+     * because of configuration update.
      */
     boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId,
             boolean markFrozenIfConfigChanged, boolean deferResume) {
@@ -2066,9 +2086,10 @@
 
     /**
      * Move stack with all its existing content to specified task display area.
-     * @param stackId Id of stack to move.
+     *
+     * @param stackId         Id of stack to move.
      * @param taskDisplayArea The task display area to move stack to.
-     * @param onTop Indicates whether container should be place on top or on bottom.
+     * @param onTop           Indicates whether container should be place on top or on bottom.
      */
     void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) {
         final Task stack = getStack(stackId);
@@ -2098,9 +2119,10 @@
 
     /**
      * Move stack with all its existing content to specified display.
-     * @param stackId Id of stack to move.
+     *
+     * @param stackId   Id of stack to move.
      * @param displayId Id of display to move stack to.
-     * @param onTop Indicates whether container should be place on top or on bottom.
+     * @param onTop     Indicates whether container should be place on top or on bottom.
      */
     void moveStackToDisplay(int stackId, int displayId, boolean onTop) {
         final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
@@ -2192,7 +2214,7 @@
                 final ActivityRecord oldTopActivity = task.getTopMostActivity();
                 if (oldTopActivity != null && oldTopActivity.isState(STOPPED)
                         && task.getDisplayContent().mAppTransition.getAppTransition()
-                                == TRANSIT_TASK_TO_BACK) {
+                        == TRANSIT_TASK_TO_BACK) {
                     task.getDisplayContent().mClosingApps.add(oldTopActivity);
                     oldTopActivity.mRequestForceTransition = true;
                 }
@@ -2227,6 +2249,7 @@
 
     /**
      * Notifies when an activity enters or leaves PIP mode.
+     *
      * @param r indicates the activity currently in PIP, can be null to indicate no activity is
      *          currently in PIP mode.
      */
@@ -2249,7 +2272,7 @@
 
     @Nullable
     ActivityRecord findTask(ActivityRecord r, TaskDisplayArea preferredTaskDisplayArea) {
-        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
+        ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s", r);
         mTmpFindTaskResult.clear();
 
         // Looking up task on preferred display area first
@@ -2277,13 +2300,16 @@
             return task;
         }
 
-        if (DEBUG_TASKS && mTmpFindTaskResult.mRecord == null) Slog.d(TAG_TASKS, "No task found");
+        if (WM_DEBUG_TASKS.isEnabled() && mTmpFindTaskResult.mRecord == null) {
+            ProtoLog.d(WM_DEBUG_TASKS, "No task found");
+        }
         return mTmpFindTaskResult.mRecord;
     }
 
     /**
      * Finish the topmost activities in all stacks that belong to the crashed app.
-     * @param app The app that crashed.
+     *
+     * @param app    The app that crashed.
      * @param reason Reason to perform this action.
      * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
      */
@@ -2751,9 +2777,11 @@
     private void destroyActivity(ActivityRecord r) {
         if (r.finishing || !r.isDestroyable()) return;
 
-        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.getState()
-                + " resumed=" + r.getStack().mResumedActivity + " pausing="
-                + r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
+        if (DEBUG_SWITCH) {
+            Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.getState()
+                    + " resumed=" + r.getStack().mResumedActivity + " pausing="
+                    + r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
+        }
 
         r.destroyImmediately(mDestroyAllActivitiesReason);
     }
@@ -2814,7 +2842,7 @@
 
     private static boolean matchesActivity(ActivityRecord r, int userId,
             boolean compareIntentFilters, Intent intent, ComponentName cls) {
-        if (!r.canBeTopRunning() || r.mUserId != userId)  return false;
+        if (!r.canBeTopRunning() || r.mUserId != userId) return false;
 
         if (compareIntentFilters) {
             if (r.intent.filterEquals(intent)) {
@@ -2849,10 +2877,10 @@
     /**
      * Returns the right stack to use for launching factoring in all the input parameters.
      *
-     * @param r The activity we are trying to launch. Can be null.
-     * @param options The activity options used to the launch. Can be null.
-     * @param candidateTask The possible task the activity might be launched in. Can be null.
-     * @param launchParams The resolved launch params to use.
+     * @param r              The activity we are trying to launch. Can be null.
+     * @param options        The activity options used to the launch. Can be null.
+     * @param candidateTask  The possible task the activity might be launched in. Can be null.
+     * @param launchParams   The resolved launch params to use.
      * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
      * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
      * @return The stack to use for the launch or INVALID_STACK_ID.
@@ -2986,9 +3014,10 @@
     /**
      * Get a topmost stack on the display area, that is a valid launch stack for specified activity.
      * If there is no such stack, new dynamic stack can be created.
+     *
      * @param taskDisplayArea Target display area.
-     * @param r Activity that should be launched there.
-     * @param candidateTask The possible task the activity might be put in.
+     * @param r               Activity that should be launched there.
+     * @param candidateTask   The possible task the activity might be put in.
      * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
      */
     @VisibleForTesting
@@ -3054,10 +3083,14 @@
     // TODO: Can probably be consolidated into getLaunchStack()...
     private boolean isValidLaunchStack(Task stack, ActivityRecord r, int windowingMode) {
         switch (stack.getActivityType()) {
-            case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome();
-            case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents();
-            case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant();
-            case ACTIVITY_TYPE_DREAM: return r.isActivityTypeDream();
+            case ACTIVITY_TYPE_HOME:
+                return r.isActivityTypeHome();
+            case ACTIVITY_TYPE_RECENTS:
+                return r.isActivityTypeRecents();
+            case ACTIVITY_TYPE_ASSISTANT:
+                return r.isActivityTypeAssistant();
+            case ACTIVITY_TYPE_DREAM:
+                return r.isActivityTypeDream();
         }
         if (stack.mCreatedByOrganizer) {
             // Don't launch directly into task created by organizer...but why can't we?
@@ -3097,9 +3130,9 @@
      * from the target stack. If no valid candidates will be found, it will then go through all
      * displays and stacks in last-focused order.
      *
-     * @param currentFocus The stack that previously had focus.
+     * @param currentFocus  The stack that previously had focus.
      * @param ignoreCurrent If we should ignore {@param currentFocus} when searching for next
-     *                     candidate.
+     *                      candidate.
      * @return Next focusable {@link Task}, {@code null} if not found.
      */
     Task getNextFocusableStack(@NonNull Task currentFocus,
@@ -3162,6 +3195,7 @@
 
     FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper =
             new FinishDisabledPackageActivitiesHelper();
+
     class FinishDisabledPackageActivitiesHelper {
         private String mPackageName;
         private Set<String> mFilterByClasses;
@@ -3318,10 +3352,8 @@
             }
             final ActivityRecord resumedActivity = stack.getResumedActivity();
             if (resumedActivity == null || !resumedActivity.idle) {
-                if (DEBUG_STATES) {
-                    Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack="
-                            + stack.getRootTaskId() + " " + resumedActivity + " not idle");
-                }
+                ProtoLog.d(WM_DEBUG_STATES, "allResumedActivitiesIdle: stack=%d %s "
+                        + "not idle", stack.getRootTaskId(), resumedActivity);
                 return false;
             }
         }
@@ -3360,9 +3392,9 @@
                         final Task stack = taskDisplayArea.getStackAt(sNdx);
                         final ActivityRecord r = stack.mPausingActivity;
                         if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) {
-                            if (DEBUG_STATES) {
-                                Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r
-                                        + " state=" + r.getState());
+                            ProtoLog.d(WM_DEBUG_STATES, "allPausedActivitiesComplete: "
+                                    + "r=%s state=%s", r, r.getState());
+                            if (WM_DEBUG_STATES.isEnabled()) {
                                 pausing[0] = false;
                             } else {
                                 return true;
@@ -3441,10 +3473,11 @@
 
     /**
      * Returns a {@link Task} for the input id if available. {@code null} otherwise.
-     * @param id Id of the task we would like returned.
+     *
+     * @param id        Id of the task we would like returned.
      * @param matchMode The mode to match the given task id in.
-     * @param aOptions The activity options to use for restoration. Can be null.
-     * @param onTop If the stack for the task should be the topmost on the display.
+     * @param aOptions  The activity options to use for restoration. Can be null.
+     * @param onTop     If the stack for the task should be the topmost on the display.
      */
     Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode,
             @Nullable ActivityOptions aOptions, boolean onTop) {
@@ -3499,8 +3532,10 @@
 
         // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
         if (!mStackSupervisor.restoreRecentTaskLocked(task, aOptions, onTop)) {
-            if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
-                    "Couldn't restore task id=" + id + " found in recents");
+            if (DEBUG_RECENTS) {
+                Slog.w(TAG_RECENTS,
+                        "Couldn't restore task id=" + id + " found in recents");
+            }
             return null;
         }
         if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents");
@@ -3611,14 +3646,19 @@
 
     /**
      * Dump all connected displays' configurations.
+     *
      * @param prefix Prefix to apply to each line of the dump.
      */
     void dumpDisplayConfigs(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.println("Display override configurations:");
+        pw.print(prefix);
+        pw.println("Display override configurations:");
         final int displayCount = getChildCount();
         for (int i = 0; i < displayCount; i++) {
             final DisplayContent displayContent = getChildAt(i);
-            pw.print(prefix); pw.print("  "); pw.print(displayContent.mDisplayId); pw.print(": ");
+            pw.print(prefix);
+            pw.print("  ");
+            pw.print(displayContent.mDisplayId);
+            pw.print(": ");
             pw.println(displayContent.getRequestedOverrideConfiguration());
         }
     }
@@ -3632,7 +3672,8 @@
             if (printed[0]) {
                 pw.println();
             }
-            pw.print("Display #"); pw.print(displayContent.mDisplayId);
+            pw.print("Display #");
+            pw.print(displayContent.mDisplayId);
             pw.println(" (activities from top to bottom):");
             displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
                 for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 14230cd..f984576 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -80,6 +80,8 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -87,13 +89,9 @@
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
 import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
@@ -1280,7 +1278,7 @@
                     _intent.setSourceBounds(null);
                 }
             }
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
+            ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to %s", this, _intent);
             intent = _intent;
             realActivity = _intent != null ? _intent.getComponent() : null;
             origActivity = null;
@@ -1291,8 +1289,7 @@
                 Intent targetIntent = new Intent(_intent);
                 targetIntent.setSelector(null);
                 targetIntent.setSourceBounds(null);
-                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
-                        "Setting Intent of " + this + " to target " + targetIntent);
+                ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to target %s", this, targetIntent);
                 intent = targetIntent;
                 realActivity = targetComponent;
                 origActivity = _intent.getComponent();
@@ -5317,8 +5314,8 @@
     }
 
     void minimalResumeActivityLocked(ActivityRecord r) {
-        if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
-                + " callers=" + Debug.getCallers(5));
+        ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (starting new instance) "
+                + "callers=%s", r, Debug.getCallers(5));
         r.setState(RESUMED, "minimalResumeActivityLocked");
         r.completeResumeLocked();
     }
@@ -5362,7 +5359,7 @@
 
         if (mResumedActivity != null) {
             // Still have something resumed; can't sleep until it is paused.
-            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
+            ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity);
             if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                     "Sleep => pause with userLeaving=false");
 
@@ -5371,15 +5368,15 @@
             shouldSleep = false ;
         } else if (mPausingActivity != null) {
             // Still waiting for something to pause; can't sleep yet.
-            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
+            ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity);
             shouldSleep = false;
         }
 
         if (!shuttingDown) {
             if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) {
                 // Still need to tell some activities to stop; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
-                        + mStackSupervisor.mStoppingActivities.size() + " activities");
+                ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities",
+                        mStackSupervisor.mStoppingActivities.size());
 
                 mStackSupervisor.scheduleIdle();
                 shouldSleep = false;
@@ -5458,8 +5455,7 @@
             return false;
         }
 
-        if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev);
-        else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
+        ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
         mPausingActivity = prev;
         mLastPausedActivity = prev;
         mLastNoHistoryActivity = prev.isNoHistory() ? prev : null;
@@ -5490,13 +5486,13 @@
         boolean didAutoPip = false;
         if (prev.attachedToProcess()) {
             if (shouldAutoPip) {
-                if (DEBUG_PAUSE) {
-                    Slog.d(TAG_PAUSE, "Auto-PIP allowed, entering PIP mode directly: " + prev);
-                }
+                ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
+                        + "directly: %s", prev);
+
                 didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);
                 mPausingActivity = null;
             } else {
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
+                ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
                 try {
                     EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
                             prev.shortComponentName, "userLeaving=" + userLeaving, reason);
@@ -5536,8 +5532,8 @@
             // key dispatch; the same activity will pick it up again on wakeup.
             if (!uiSleeping) {
                 prev.pauseKeyDispatchingLocked();
-            } else if (DEBUG_PAUSE) {
-                Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
+            } else {
+                ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");
             }
 
             if (pauseImmediately) {
@@ -5554,7 +5550,7 @@
         } else {
             // This activity failed to schedule the
             // pause, so just treat it as being paused now.
-            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
+            ProtoLog.v(WM_DEBUG_STATES, "Activity not running, resuming next.");
             if (resuming == null) {
                 mRootWindowContainer.resumeFocusedStacksTopActivities();
             }
@@ -5565,22 +5561,22 @@
     @VisibleForTesting
     void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
         ActivityRecord prev = mPausingActivity;
-        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
+        ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);
 
         if (prev != null) {
             prev.setWillCloseOrEnterPip(false);
             final boolean wasStopping = prev.isState(STOPPING);
             prev.setState(PAUSED, "completePausedLocked");
             if (prev.finishing) {
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
+                ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
                 prev = prev.completeFinishing("completePausedLocked");
             } else if (prev.hasProcess()) {
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
-                        + " wasStopping=" + wasStopping
-                        + " visibleRequested=" + prev.mVisibleRequested);
+                ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
+                        + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
+                        prev.mVisibleRequested);
                 if (prev.deferRelaunchUntilPaused) {
                     // Complete the deferred relaunch that was waiting for pause to complete.
-                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
+                    ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev);
                     prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
                 } else if (wasStopping) {
                     // We are also stopping, the stop request must have gone soon after the pause.
@@ -5596,7 +5592,7 @@
                             "completePauseLocked");
                 }
             } else {
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
+                ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev);
                 prev = null;
             }
             // It is possible the activity was freezing the screen before it was paused.
@@ -5892,8 +5888,8 @@
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             executeAppTransition(options);
-            if (DEBUG_STATES) Slog.d(TAG_STATES,
-                    "resumeTopActivityLocked: Top activity resumed " + next);
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity "
+                    + "resumed %s", next);
             return false;
         }
 
@@ -5904,9 +5900,9 @@
         // If we are currently pausing an activity, then don't do anything until that is done.
         final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
         if (!allPausedComplete) {
-            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) {
-                Slog.v(TAG_PAUSE, "resumeTopActivityLocked: Skip resume: some activity pausing.");
-            }
+            ProtoLog.v(WM_DEBUG_STATES,
+                    "resumeTopActivityLocked: Skip resume: some activity pausing.");
+
             return false;
         }
 
@@ -5918,8 +5914,8 @@
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             executeAppTransition(options);
-            if (DEBUG_STATES) Slog.d(TAG_STATES,
-                    "resumeTopActivityLocked: Going to sleep and all paused");
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Going to sleep and"
+                    + " all paused");
             return false;
         }
 
@@ -5941,7 +5937,7 @@
 
         // If we are currently pausing an activity, then don't do anything until that is done.
         if (!mRootWindowContainer.allPausedActivitiesComplete()) {
-            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
+            ProtoLog.v(WM_DEBUG_STATES,
                     "resumeTopActivityLocked: Skip resume: some activity pausing.");
 
             return false;
@@ -5967,14 +5963,13 @@
 
         boolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next);
         if (mResumedActivity != null) {
-            if (DEBUG_STATES) Slog.d(TAG_STATES,
-                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
             pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next,
-                "resumeTopActivityInnerLocked");
+                    "resumeTopActivityInnerLocked");
         }
         if (pausing) {
-            if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
-                    "resumeTopActivityLocked: Skip resume: need to start pausing");
+            ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: need to"
+                    + " start pausing");
             // At this point we want to put the upcoming activity's process
             // at the top of the LRU list, since we know we will be needing it
             // very soon and it would be a waste to let it get killed if it
@@ -6003,8 +5998,8 @@
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             executeAppTransition(options);
-            if (DEBUG_STATES) Slog.d(TAG_STATES,
-                    "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity resumed "
+                    + "(dontWaitForPause) %s", next);
             return true;
         }
 
@@ -6014,8 +6009,8 @@
         if (shouldSleepActivities() && mLastNoHistoryActivity != null
                 && !mLastNoHistoryActivity.finishing
                 && mLastNoHistoryActivity != next) {
-            if (DEBUG_STATES) Slog.d(TAG_STATES,
-                    "no-history finish of " + mLastNoHistoryActivity + " on new resume");
+            ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s on new resume",
+                    mLastNoHistoryActivity);
             mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */);
             mLastNoHistoryActivity = null;
         }
@@ -6134,8 +6129,7 @@
 
             mAtmService.updateCpuStats();
 
-            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
-                    + " (in existing)");
+            ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);
 
             next.setState(RESUMED, "resumeTopActivityInnerLocked");
 
@@ -6165,9 +6159,8 @@
                 // is still at the top and schedule another run if something
                 // weird happened.
                 ActivityRecord nextNext = topRunningActivity();
-                if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
-                        "Activity config changed during resume: " + next
-                                + ", new next: " + nextNext);
+                ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
+                        + "%s, new next: %s", next, nextNext);
                 if (nextNext != next) {
                     // Do over!
                     mStackSupervisor.scheduleResumeTopActivities();
@@ -6214,12 +6207,11 @@
                                 dc.isNextTransitionForward()));
                 mAtmService.getLifecycleManager().scheduleTransaction(transaction);
 
-                if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
-                        + next);
+                ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Resumed %s", next);
             } catch (Exception e) {
                 // Whoops, need to restart this activity!
-                if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
-                        + lastState + ": " + next);
+                ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
+                        + "%s", lastState, next);
                 next.setState(lastState, "resumeTopActivityInnerLocked");
 
                 // lastResumedActivity being non-null implies there is a lastStack present.
@@ -6261,7 +6253,7 @@
                 }
                 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
             }
-            if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Restarting %s", next);
             mStackSupervisor.startSpecificActivity(next, true, true);
         }
 
@@ -6293,8 +6285,8 @@
         // If the current stack is a home stack, or if focus didn't switch to a different stack -
         // just start up the Launcher...
         ActivityOptions.abort(options);
-        if (DEBUG_STATES) Slog.d(TAG_STATES,
-                "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home");
+        ProtoLog.d(WM_DEBUG_STATES, "resumeNextFocusableActivityWhenStackIsEmpty: %s, "
+                + "go home", reason);
         return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea());
     }
 
@@ -7022,8 +7014,8 @@
     boolean handleAppDied(WindowProcessController app) {
         boolean isPausingDied = false;
         if (mPausingActivity != null && mPausingActivity.app == app) {
-            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
-                    "App died while pausing: " + mPausingActivity);
+            ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s",
+                    mPausingActivity);
             mPausingActivity = null;
             isPausingDied = true;
         }
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 2c8770f..696e1ca 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -33,12 +33,10 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
 import static com.android.server.wm.DisplayContent.alwaysCreateStack;
-import static com.android.server.wm.RootWindowContainer.TAG_STATES;
 import static com.android.server.wm.Task.ActivityState.RESUMED;
 import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -212,11 +210,13 @@
         return mChildren.indexOf(task);
     }
 
-    @Nullable Task getRootHomeTask() {
+    @Nullable
+    Task getRootHomeTask() {
         return mRootHomeTask;
     }
 
-    @Nullable Task getRootRecentsTask() {
+    @Nullable
+    Task getRootRecentsTask() {
         return mRootRecentsTask;
     }
 
@@ -526,19 +526,20 @@
      * When stack is added or repositioned, find a proper position for it.
      *
      * The order is defined as:
-     *  - Dream is on top of everything
-     *  - PiP is directly below the Dream
-     *  - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
-     *    existing ones
-     *  - other non-always-on-top stacks come directly below always-on-top stacks; new
-     *    non-always-on-top stacks are added directly below always-on-top stacks and above existing
-     *    non-always-on-top stacks
-     *  - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
-     *    (including the Dream); otherwise, it is a normal non-always-on-top stack
+     * - Dream is on top of everything
+     * - PiP is directly below the Dream
+     * - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
+     * existing ones
+     * - other non-always-on-top stacks come directly below always-on-top stacks; new
+     * non-always-on-top stacks are added directly below always-on-top stacks and above existing
+     * non-always-on-top stacks
+     * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
+     * (including the Dream); otherwise, it is a normal non-always-on-top stack
      *
      * @param requestedPosition Position requested by caller.
-     * @param stack Stack to be added or positioned.
-     * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
+     * @param stack             Stack to be added or positioned.
+     * @param adding            Flag indicates whether we're adding a new stack or positioning an
+     *                          existing.
      * @return The proper position for the stack.
      */
     private int findPositionForStack(int requestedPosition, Task stack, boolean adding) {
@@ -655,6 +656,7 @@
 
     /**
      * Sets whether the task display area should ignore fixed-orientation request from apps.
+     *
      * @return Whether the display orientation changed
      */
     boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
@@ -774,7 +776,7 @@
      * Adjusts the layer of the stack which belongs to the same group.
      * Note that there are three stack groups: home stacks, always on top stacks, and normal stacks.
      *
-     * @param startLayer The beginning layer of this group of stacks.
+     * @param startLayer   The beginning layer of this group of stacks.
      * @param normalStacks Set {@code true} if this group is neither home nor always on top.
      * @return The adjusted layer value.
      */
@@ -921,6 +923,7 @@
     /**
      * Returns an existing stack compatible with the windowing mode and activity type or creates one
      * if a compatible stack doesn't exist.
+     *
      * @see #getOrCreateStack(int, int, boolean, Intent, Task)
      */
     Task getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
@@ -933,6 +936,7 @@
      * existing compatible root task or creates a new one.
      * For one level task, the candidate task would be reused to also be the root task or create
      * a new root task if no candidate task.
+     *
      * @see #getStack(int, int)
      * @see #createStack(int, int, boolean)
      */
@@ -978,6 +982,7 @@
     /**
      * Returns an existing stack compatible with the input params or creates one
      * if a compatible stack doesn't exist.
+     *
      * @see #getOrCreateStack(int, int, boolean)
      */
     Task getOrCreateStack(@Nullable ActivityRecord r,
@@ -1006,17 +1011,21 @@
 
     /**
      * Creates a stack matching the input windowing mode and activity type on this display.
-     * @param windowingMode The windowing mode the stack should be created in. If
-     *                      {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
-     *                      inherit its parent's windowing mode.
-     * @param activityType The activityType the stack should be created in. If
-     *                     {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
-     *                     be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
-     * @param onTop If true the stack will be created at the top of the display, else at the bottom.
-     * @param info The started activity info.
-     * @param intent The intent that started this task.
+     *
+     * @param windowingMode      The windowing mode the stack should be created in. If
+     *                           {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack
+     *                           will
+     *                           inherit its parent's windowing mode.
+     * @param activityType       The activityType the stack should be created in. If
+     *                           {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack
+     *                           will
+     *                           be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+     * @param onTop              If true the stack will be created at the top of the display, else
+     *                           at the bottom.
+     * @param info               The started activity info.
+     * @param intent             The intent that started this task.
      * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
-     *                          otherwise.
+     *                           otherwise.
      * @return The newly created stack.
      */
     Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
@@ -1223,8 +1232,9 @@
      * paused in stacks that are no longer visible or in pinned windowing mode. This does not
      * pause activities in visible stacks, so if an activity is launched within the same stack/task,
      * then we should explicitly pause that stack's top activity.
+     *
      * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
-     * @param resuming The resuming activity.
+     * @param resuming    The resuming activity.
      * @return {@code true} if any activity was paused as a result of this call.
      */
     boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
@@ -1235,10 +1245,8 @@
             if (resumedActivity != null
                     && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
                     || !stack.isTopActivityFocusable())) {
-                if (DEBUG_STATES) {
-                    Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
-                            + " mResumedActivity=" + resumedActivity);
-                }
+                ProtoLog.d(WM_DEBUG_STATES, "pauseBackStacks: stack=%s "
+                        + "mResumedActivity=%s", stack, resumedActivity);
                 someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
                         resuming, "pauseBackStacks");
             }
@@ -1255,9 +1263,8 @@
         for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
             final Task stack = getStackAt(stackNdx);
             if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
-                if (DEBUG_TASKS) {
-                    Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
-                }
+                ProtoLog.d(WM_DEBUG_TASKS, "Skipping stack: (mismatch activity/stack) "
+                        + "%s", stack);
                 continue;
             }
 
@@ -1400,12 +1407,13 @@
 
     /**
      * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
-     * @param windowingMode The windowing mode we are checking support for.
+     *
+     * @param windowingMode       The windowing mode we are checking support for.
      * @param supportsMultiWindow If we should consider support for multi-window mode in general.
      * @param supportsSplitScreen If we should consider support for split-screen multi-window.
-     * @param supportsFreeform If we should consider support for freeform multi-window.
-     * @param supportsPip If we should consider support for picture-in-picture mutli-window.
-     * @param activityType The activity type under consideration.
+     * @param supportsFreeform    If we should consider support for freeform multi-window.
+     * @param supportsPip         If we should consider support for picture-in-picture mutli-window.
+     * @param activityType        The activity type under consideration.
      * @return true if the windowing mode is supported.
      */
     private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
@@ -1444,9 +1452,9 @@
      * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
      * display with the provided parameters.
      *
-     * @param r The ActivityRecord in question.
-     * @param options Options to start with.
-     * @param task The task within-which the activity would start.
+     * @param r            The ActivityRecord in question.
+     * @param options      Options to start with.
+     * @param task         The task within-which the activity would start.
      * @param activityType The type of activity to start.
      * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
      */
@@ -1481,9 +1489,9 @@
      * on this display.
      *
      * @param windowingMode The windowing-mode to validate.
-     * @param r The {@link ActivityRecord} to check against.
-     * @param task The {@link Task} to check against.
-     * @param activityType An activity type.
+     * @param r             The {@link ActivityRecord} to check against.
+     * @param task          The {@link Task} to check against.
+     * @param activityType  An activity type.
      * @return {@code true} if windowingMode is valid, {@code false} otherwise.
      */
     boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
@@ -1508,7 +1516,7 @@
 
         return windowingMode != WINDOWING_MODE_UNDEFINED
                 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
-                        supportsFreeform, supportsPip, activityType);
+                supportsFreeform, supportsPip, activityType);
     }
 
     /**
@@ -1516,9 +1524,9 @@
      * on this display.
      *
      * @param windowingMode The windowing-mode to validate.
-     * @param r The {@link ActivityRecord} to check against.
-     * @param task The {@link Task} to check against.
-     * @param activityType An activity type.
+     * @param r             The {@link ActivityRecord} to check against.
+     * @param task          The {@link Task} to check against.
+     * @param activityType  An activity type.
      * @return The provided windowingMode or the closest valid mode which is appropriate.
      */
     int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
@@ -1606,6 +1614,7 @@
     /**
      * Returns the existing home stack or creates and returns a new one if it should exist for the
      * display.
+     *
      * @param onTop Only be used when there is no existing home stack. If true the home stack will
      *              be created at the top of the display, else at the bottom.
      */
@@ -1743,7 +1752,7 @@
 
     /**
      * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
-     *         already top-most.
+     * already top-most.
      */
     static Task getStackAbove(Task stack) {
         final WindowContainer wc = stack.getParent();
@@ -1789,6 +1798,7 @@
 
     /**
      * Notifies of a stack order change
+     *
      * @param stack The stack which triggered the order change
      */
     void onStackOrderChanged(Task stack) {
@@ -1832,6 +1842,7 @@
 
     /**
      * Removes the stacks in the node applying the content removal node from the display.
+     *
      * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
      */
     Task remove() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 2ece30d..38ec924 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -22,6 +22,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
+import static android.content.pm.ActivityInfo.reverseOrientation;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -809,6 +810,13 @@
         return parent != null ? parent.getDisplayArea() : null;
     }
 
+    /** Get the first node of type {@link RootDisplayArea} above or at this node. */
+    @Nullable
+    RootDisplayArea getRootDisplayArea() {
+        WindowContainer parent = getParent();
+        return parent != null ? parent.getRootDisplayArea() : null;
+    }
+
     boolean isAttached() {
         return getDisplayArea() != null;
     }
@@ -1154,17 +1162,30 @@
      *         {@link Configuration#ORIENTATION_UNDEFINED}).
      */
     int getRequestedConfigurationOrientation() {
-        if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+        int requestedOrientation = mOrientation;
+        final RootDisplayArea root = getRootDisplayArea();
+        if (root != null && root.isOrientationDifferentFromDisplay()) {
+            // Reverse the requested orientation if the orientation of its root is different from
+            // the display, so that when the display rotates to the reversed orientation, the
+            // requested app will be in the requested orientation.
+            // For example, if the display is 1200x900 (landscape), and the DAG is 600x900
+            // (portrait).
+            // When an app below the DAG is requesting landscape, it should actually request the
+            // display to be portrait, so that the DAG and the app will be in landscape.
+            requestedOrientation = reverseOrientation(mOrientation);
+        }
+
+        if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
             // NOSENSOR means the display's "natural" orientation, so return that.
             if (mDisplayContent != null) {
                 return mDisplayContent.getNaturalOrientation();
             }
-        } else if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+        } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
             // LOCKED means the activity's orientation remains unchanged, so return existing value.
             return getConfiguration().orientation;
-        } else if (isFixedOrientationLandscape(mOrientation)) {
+        } else if (isFixedOrientationLandscape(requestedOrientation)) {
             return ORIENTATION_LANDSCAPE;
-        } else if (isFixedOrientationPortrait(mOrientation)) {
+        } else if (isFixedOrientationPortrait(requestedOrientation)) {
             return ORIENTATION_PORTRAIT;
         }
         return ORIENTATION_UNDEFINED;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index bbcb312..5f145f3 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -2135,6 +2135,11 @@
     return binder::Status::ok();
 }
 
+binder::Status IncrementalService::DataLoaderStub::reportStreamHealth(MountId mountId,
+                                                                      int newStatus) {
+    return binder::Status::ok();
+}
+
 bool IncrementalService::DataLoaderStub::isHealthParamsValid() const {
     return mHealthCheckParams.blockedTimeoutMs > 0 &&
             mHealthCheckParams.blockedTimeoutMs < mHealthCheckParams.unhealthyTimeoutMs;
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index d820417..504c02a 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -200,6 +200,7 @@
 
     private:
         binder::Status onStatusChanged(MountId mount, int newStatus) final;
+        binder::Status reportStreamHealth(MountId mount, int newStatus) final;
 
         sp<content::pm::IDataLoader> getDataLoader();
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 63ad53b..2a9c394 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -160,7 +160,7 @@
         assertThat(playbackDevice.getActiveSource().logicalAddress).isEqualTo(
                 playbackDevice.mAddress);
         assertThat(playbackDevice.getActiveSource().physicalAddress).isEqualTo(mPhysicalAddress);
-        assertThat(playbackDevice.mIsActiveSource).isTrue();
+        assertThat(playbackDevice.isActiveSource()).isTrue();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 415ae07..74fd683 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -30,10 +30,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.Context;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.media.AudioManager;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
 import android.os.Looper;
+import android.os.PowerManager;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 
@@ -47,6 +52,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 
@@ -81,8 +88,17 @@
     private HdmiPortInfo[] mHdmiPortInfo;
     private boolean mWokenUp;
 
+    @Mock private IPowerManager mIPowerManagerMock;
+    @Mock private IThermalService mIThermalServiceMock;
+
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        Context context = InstrumentationRegistry.getTargetContext();
+        mMyLooper = mTestLooper.getLooper();
+        PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mMyLooper));
         mHdmiControlService =
             new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
                 @Override
@@ -166,6 +182,11 @@
                             return defVal;
                     }
                 }
+
+                @Override
+                PowerManager getPowerManager() {
+                    return powerManager;
+                }
             };
 
         mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
@@ -174,11 +195,6 @@
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
         mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
             @Override
-            void setIsActiveSource(boolean on) {
-                mIsActiveSource = on;
-            }
-
-            @Override
             protected int getPreferredAddress() {
                 return ADDR_PLAYBACK_1;
             }
@@ -827,4 +843,68 @@
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(unexpected);
     }
+
+    @Test
+    public void setActiveSource_localDevice_playback() {
+        mHdmiControlService.setActiveSource(mHdmiCecLocalDevicePlayback.mAddress,
+                SELF_PHYSICAL_ADDRESS,
+                "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+                mHdmiCecLocalDevicePlayback.mAddress);
+        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+                SELF_PHYSICAL_ADDRESS);
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse();
+    }
+
+    @Test
+    public void setActiveSource_localDevice_audio() {
+        mHdmiControlService.setActiveSource(mHdmiCecLocalDeviceAudioSystem.mAddress,
+                SELF_PHYSICAL_ADDRESS,
+                "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+                mHdmiCecLocalDeviceAudioSystem.mAddress);
+        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+                SELF_PHYSICAL_ADDRESS);
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isTrue();
+    }
+
+    @Test
+    public void setActiveSource_remoteDevice() {
+        mHdmiControlService.setActiveSource(Constants.ADDR_TV, 0x0000, "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+                Constants.ADDR_TV);
+        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x000);
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse();
+    }
+
+    @Test
+    public void setActiveSource_nonCecDevice() {
+        mHdmiControlService.setActiveSource(Constants.ADDR_INVALID, 0x1234,
+                "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+                Constants.ADDR_INVALID);
+        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x1234);
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse();
+    }
+
+    @Test
+    public void setActiveSource_unknown() {
+        mHdmiControlService.setActiveSource(Constants.ADDR_INVALID,
+                Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+                Constants.ADDR_INVALID);
+        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+                Constants.INVALID_PHYSICAL_ADDRESS);
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 498ebf4..7cbf571 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -17,6 +17,7 @@
 
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_INVALID;
 import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 
@@ -266,106 +267,197 @@
     @Test
     public void handleRoutingChange_otherDevice_None() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                0x5000);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                ADDR_INVALID);
+        assertThat(mStandby).isFalse();
+    }
+
+    @Test
+    public void handleRoutingChange_sameDevice_None_ActiveSource() {
+        mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+        mStandby = false;
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
+                        mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                mPlaybackLogicalAddress);
+        assertThat(mStandby).isFalse();
+    }
+
+    @Test
+    public void handleRoutingChange_sameDevice_None_InactiveSource() {
+        mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
+        mStandby = false;
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
+                        mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                ADDR_INVALID);
         assertThat(mStandby).isFalse();
     }
 
     @Test
     public void handleRoutingChange_otherDevice_StandbyNow() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mStandby).isTrue();
     }
 
     @Test
     public void handleRoutingChange_otherDevice_StandbyNow_InactiveSource() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mStandby).isFalse();
     }
 
     @Test
     public void handleRoutingChange_sameDevice_StandbyNow_ActiveSource() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
                         mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
         assertThat(mStandby).isFalse();
     }
 
     @Test
     public void handleRoutingInformation_otherDevice_None() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+        mStandby = false;
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
+        assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                0x5000);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                ADDR_INVALID);
+        assertThat(mStandby).isFalse();
+    }
+
+    @Test
+    public void handleRoutingInformation_sameDevice_None_ActiveSource() {
+        mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
-                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
+                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
+                        mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                mPlaybackLogicalAddress);
+        assertThat(mStandby).isFalse();
+    }
+
+    @Test
+    public void handleRoutingInformation_sameDevice_None_InactiveSource() {
+        mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
+        mStandby = false;
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
+                        mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                ADDR_INVALID);
         assertThat(mStandby).isFalse();
     }
 
     @Test
     public void handleRoutingInformation_otherDevice_StandbyNow() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mStandby).isTrue();
     }
 
     @Test
     public void handleRoutingInformation_otherDevice_StandbyNow_InactiveSource() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mStandby).isFalse();
     }
 
     @Test
     public void handleRoutingInformation_sameDevice_StandbyNow_ActiveSource() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
                         mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
         assertThat(mStandby).isFalse();
     }
 
@@ -430,7 +522,8 @@
         mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
                 Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
@@ -449,7 +542,8 @@
         mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
                 Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
@@ -468,7 +562,8 @@
         mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
                 Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
@@ -487,7 +582,8 @@
         mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
                 Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
@@ -506,7 +602,8 @@
         mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
                 Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
@@ -525,7 +622,8 @@
         mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
                 Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
@@ -549,6 +647,11 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mStandby).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                mPlaybackLogicalAddress);
     }
 
     @Test
@@ -560,6 +663,11 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mStandby).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                0x0000);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                ADDR_TV);
     }
 
     @Test
@@ -572,6 +680,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mStandby).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
     }
 
     @Test
@@ -583,6 +692,7 @@
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mStandby).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
     }
 
     @Test
@@ -703,7 +813,7 @@
                 mPlaybackLogicalAddress, ADDR_TV);
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
         assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
     }
 
@@ -723,7 +833,7 @@
                 mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
         assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
     }
 
@@ -742,7 +852,7 @@
                 mPlaybackLogicalAddress, ADDR_TV);
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
     }
 
@@ -761,7 +871,7 @@
                 mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
     }
 
@@ -805,21 +915,28 @@
         mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
         mTestLooper.dispatchAll();
 
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
                 mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress());
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
     }
 
     @Test
     public void handleSetStreamPath_otherDevice_None() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                0x5000);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                ADDR_INVALID);
         assertThat(mStandby).isFalse();
     }
 
@@ -827,12 +944,13 @@
     public void handleSetStreamPath_otherDevice_StandbyNow() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
             HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mStandby).isTrue();
     }
 
@@ -840,12 +958,13 @@
     public void handleSetStreamPath_otherDevice_StandbyNow_InactiveSource() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
             HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
-        mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000);
         assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
-        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
         assertThat(mStandby).isFalse();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
index 7560a34..c4068d3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
@@ -138,11 +138,6 @@
 
         mPlaybackDevice = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
             @Override
-            void setIsActiveSource(boolean on) {
-                mIsActiveSource = on;
-            }
-
-            @Override
             protected void wakeUpIfActiveSource() {}
 
             @Override
@@ -186,13 +181,13 @@
             }
         });
         assertEquals(mResult, -1);
-        assertThat(mPlaybackDevice.mIsActiveSource).isFalse();
+        assertThat(mPlaybackDevice.isActiveSource()).isFalse();
 
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
         assertThat(mHdmiControlService.isAddressAllocated()).isTrue();
         assertEquals(mResult, HdmiControlManager.RESULT_SUCCESS);
-        assertThat(mPlaybackDevice.mIsActiveSource).isTrue();
+        assertThat(mPlaybackDevice.isActiveSource()).isTrue();
     }
 
     @Test
@@ -207,6 +202,6 @@
             }
         });
         assertEquals(mResult, HdmiControlManager.RESULT_SUCCESS);
-        assertThat(mPlaybackDevice.mIsActiveSource).isTrue();
+        assertThat(mPlaybackDevice.isActiveSource()).isTrue();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 4849dd4..2f48b5e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -405,82 +405,6 @@
         assertThat(callback2.mVolumeControlEnabled).isTrue();
     }
 
-    @Test
-    public void setActiveSource_localDevice_playback() {
-        int physicalAddress = 0x1000;
-        mNativeWrapper.setPhysicalAddress(physicalAddress);
-
-        mHdmiControlService.setActiveSource(mMyPlaybackDevice.mAddress, physicalAddress,
-                "HdmiControlServiceTest");
-
-        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
-                mMyPlaybackDevice.mAddress);
-        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
-                physicalAddress);
-        assertThat(mMyPlaybackDevice.mIsActiveSource).isTrue();
-        assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
-    }
-
-    @Test
-    public void setActiveSource_localDevice_audio() {
-        int physicalAddress = 0x1000;
-        mNativeWrapper.setPhysicalAddress(physicalAddress);
-
-        mHdmiControlService.setActiveSource(mMyAudioSystemDevice.mAddress, physicalAddress,
-                "HdmiControlServiceTest");
-
-        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
-                mMyAudioSystemDevice.mAddress);
-        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
-                physicalAddress);
-        assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
-        assertThat(mMyAudioSystemDevice.mIsActiveSource).isTrue();
-    }
-
-    @Test
-    public void setActiveSource_remoteDevice() {
-        int physicalAddress = 0x1000;
-        mNativeWrapper.setPhysicalAddress(physicalAddress);
-
-        mHdmiControlService.setActiveSource(Constants.ADDR_TV, 0x0000, "HdmiControlServiceTest");
-
-        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
-                Constants.ADDR_TV);
-        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x000);
-        assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
-        assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
-    }
-
-    @Test
-    public void setActiveSource_nonCecDevice() {
-        int physicalAddress = 0x1000;
-        mNativeWrapper.setPhysicalAddress(physicalAddress);
-
-        mHdmiControlService.setActiveSource(Constants.ADDR_INVALID, 0x1234,
-                "HdmiControlServiceTest");
-
-        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
-                Constants.ADDR_INVALID);
-        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x1234);
-        assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
-        assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
-    }
-
-    @Test
-    public void setActiveSource_unknown() {
-        int physicalAddress = 0x1000;
-        mNativeWrapper.setPhysicalAddress(physicalAddress);
-
-        mHdmiControlService.setActiveSource(Constants.ADDR_INVALID,
-                Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
-
-        assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
-                Constants.ADDR_INVALID);
-        assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
-                Constants.INVALID_PHYSICAL_ADDRESS);
-        assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
-        assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
-    }
 
     private static class VolumeControlFeatureCallback extends
             IHdmiCecVolumeControlFeatureListener.Stub {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index c734242..6be28d9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -150,7 +150,7 @@
 
                     @Override
                     public void setAndBroadcastActiveSourceFromOneDeviceType(
-                            int sourceAddress, int physicalAddress) {
+                            int sourceAddress, int physicalAddress, String caller) {
                         mBroadcastActiveSource = true;
                     }
 
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
index 9ee9259..292b7c6 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
@@ -77,6 +77,7 @@
     private TestThreadingDomain mTestThreadingDomain;
     private TestCallback mTestCallback;
     private TestLocationTimeZoneProvider mTestPrimaryLocationTimeZoneProvider;
+    private TestLocationTimeZoneProvider mTestSecondaryLocationTimeZoneProvider;
 
     @Before
     public void setUp() {
@@ -87,26 +88,30 @@
         mTestCallback = new TestCallback(mTestThreadingDomain);
         mTestPrimaryLocationTimeZoneProvider =
                 new TestLocationTimeZoneProvider(mTestThreadingDomain, "primary");
+        mTestSecondaryLocationTimeZoneProvider =
+                new TestLocationTimeZoneProvider(mTestThreadingDomain, "secondary");
     }
 
     @Test
     public void initialState_enabled() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
         Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
                 .plus(testEnvironment.getProviderInitializationTimeoutFuzz());
 
-        // Initialize. After initialization the provider must be initialized and should be
+        // Initialize. After initialization the providers must be initialized and one should be
         // enabled.
         controllerImpl.initialize(testEnvironment, mTestCallback);
 
         mTestPrimaryLocationTimeZoneProvider.assertInitialized();
+        mTestSecondaryLocationTimeZoneProvider.assertInitialized();
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
@@ -114,17 +119,19 @@
     @Test
     public void initialState_disabled() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
 
-        // Initialize. After initialization the provider must be initialized but should not be
+        // Initialize. After initialization the providers must be initialized but neither should be
         // enabled.
         controllerImpl.initialize(testEnvironment, mTestCallback);
 
         mTestPrimaryLocationTimeZoneProvider.assertInitialized();
+        mTestSecondaryLocationTimeZoneProvider.assertInitialized();
 
         mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
@@ -132,7 +139,7 @@
     @Test
     public void enabled_uncertaintySuggestionSentIfNoEventReceived() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -141,6 +148,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -148,9 +156,24 @@
         mTestThreadingDomain.executeNext();
 
         // The primary should have reported uncertainty, which should trigger the controller to
-        // start the uncertainty timeout.
+        // start the uncertainty timeout and enable the secondary.
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // Simulate time passing with no provider event being received from either the primary or
+        // secondary.
+        mTestThreadingDomain.executeNext();
+
+        // Now both initialization timeouts should have triggered. The uncertainty timeout should
+        // still not be triggered.
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
 
@@ -160,6 +183,8 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
@@ -167,7 +192,7 @@
     @Test
     public void enabled_eventReceivedBeforeInitializationTimeout() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -176,6 +201,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -186,6 +212,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -194,7 +221,7 @@
     @Test
     public void enabled_eventReceivedFromPrimaryAfterInitializationTimeout() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -203,6 +230,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -211,16 +239,59 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
 
         // Simulate a location event being received from the primary provider. This should cause a
-        // suggestion to be made.
+        // suggestion to be made and the secondary to be shut down.
         mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestCallback.assertSuggestionMadeAndCommit(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+    }
+
+    @Test
+    public void enabled_eventReceivedFromSecondaryAfterInitializationTimeout() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        // Initialize and check initial state.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate time passing with no provider event being received from the primary.
+        mTestThreadingDomain.executeNext();
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // Simulate a location event being received from the secondary provider. This should cause a
+        // suggestion to be made.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -229,7 +300,7 @@
     @Test
     public void enabled_repeatedPrimaryCertainty() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -238,6 +309,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -248,6 +320,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -258,6 +331,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -267,15 +341,16 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
 
     @Test
-    public void enabled_uncertaintyTriggersASuggestionAfterUncertaintyTimeout() {
+    public void enabled_repeatedSecondaryCertainty() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -284,6 +359,70 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate time passing with no provider event being received from the primary.
+        mTestThreadingDomain.executeNext();
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // Simulate a location event being received from the secondary provider. This should cause a
+        // suggestion to be made.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertSuggestionMadeAndCommit(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // A second, identical event should not cause another suggestion.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // And a third, different event should cause another suggestion.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertSuggestionMadeAndCommit(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+    }
+
+    @Test
+    public void enabled_uncertaintyTriggersASuggestionAfterUncertaintyTimeout() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        // Initialize and check initial state.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -294,18 +433,48 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
         // Simulate an uncertain event being received from the primary provider. This should not
         // cause a suggestion to be made straight away, but the uncertainty timeout should be
-        // started.
+        // started and the secondary should be enabled.
         mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // Simulate a location event being received from the secondary provider. This should cause a
+        // suggestion to be made, cancel the uncertainty timeout and ensure the secondary is
+        // considered initialized.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertSuggestionMadeAndCommit(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate an uncertain event being received from the secondary provider. This should not
+        // cause a suggestion to be made straight away, but the uncertainty timeout should be
+        // started. Both providers are now enabled, with no initialization timeout set.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
 
@@ -315,6 +484,8 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
@@ -322,7 +493,7 @@
     @Test
     public void enabled_briefUncertaintyTriggersNoSuggestion() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -331,6 +502,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -341,27 +513,32 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
         // Uncertainty should not cause a suggestion to be made straight away, but the uncertainty
-        // timeout should be started.
+        // timeout should be started and the secondary should be enabled.
         mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
                 USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
         mTestCallback.assertNoSuggestionMade();
         assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
 
         // And a success event from the primary provider should cause the controller to make another
-        // suggestion, the uncertainty timeout should be cancelled.
+        // suggestion, the uncertainty timeout should be cancelled and the secondary should be
+        // disabled again.
         mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -370,7 +547,7 @@
     @Test
     public void configChanges_enableAndDisableWithNoPreviousSuggestion() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
 
@@ -378,6 +555,7 @@
         controllerImpl.initialize(testEnvironment, mTestCallback);
 
         mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -386,6 +564,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -393,6 +572,7 @@
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
 
         mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
@@ -400,7 +580,7 @@
     @Test
     public void configChanges_enableAndDisableWithPreviousSuggestion() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
 
@@ -408,6 +588,7 @@
         controllerImpl.initialize(testEnvironment, mTestCallback);
 
         mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -416,6 +597,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -425,6 +607,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -436,6 +619,7 @@
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
 
         mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
@@ -443,7 +627,7 @@
     @Test
     public void configChanges_userSwitch_enabledToEnabled() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -452,6 +636,7 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -463,6 +648,7 @@
         // and also clear the scheduled uncertainty suggestion.
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertSuggestionMadeAndCommit(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -477,13 +663,14 @@
         mTestPrimaryLocationTimeZoneProvider.assertStateChangesAndCommit(expectedStateTransitions);
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfig(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER2_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
 
     @Test
-    public void primaryPermFailure_disableAndEnable() {
+    public void primaryPermFailure_secondaryEventsReceived() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
-                mTestPrimaryLocationTimeZoneProvider);
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
@@ -492,22 +679,86 @@
 
         mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
                 PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
         // Simulate a failure location event being received from the primary provider. This should
-        // cause an uncertain suggestion to be made.
+        // cause the secondary to be enabled.
         mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
                 USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
 
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
-        mTestCallback.assertUncertainSuggestionMadeAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate uncertainty from the secondary.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // And a success event from the secondary provider should cause the controller to make
+        // another suggestion, the uncertainty timeout should be cancelled.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertSuggestionMadeAndCommit(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate uncertainty from the secondary.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+    }
+
+    @Test
+    public void primaryPermFailure_disableAndEnable() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        // Initialize and check initial state.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate a failure location event being received from the primary provider. This should
+        // cause the secondary to be enabled.
+        mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
         // Now signal a config change so that geo detection is disabled.
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
 
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
         mTestCallback.assertNoSuggestionMade();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
 
@@ -515,6 +766,164 @@
         testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
 
         mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+    }
+
+    @Test
+    public void secondaryPermFailure_primaryEventsReceived() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        // Initialize and check initial state.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate an uncertain event from the primary. This will enable the secondary, which will
+        // give this test the opportunity to simulate its failure. Then it will be possible to
+        // demonstrate controller behavior with only the primary working.
+        mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // Simulate failure event from the secondary. This should just affect the secondary's state.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // And a success event from the primary provider should cause the controller to make
+        // a suggestion, the uncertainty timeout should be cancelled.
+        mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertSuggestionMadeAndCommit(
+                USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate uncertainty from the primary. The secondary cannot be enabled.
+        mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+    }
+
+    @Test
+    public void secondaryPermFailure_disableAndEnable() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        // Initialize and check initial state.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate an uncertain event from the primary. This will enable the secondary, which will
+        // give this test the opportunity to simulate its failure. Then it will be possible to
+        // demonstrate controller behavior with only the primary working.
+        mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // Simulate failure event from the secondary. This should just affect the secondary's state.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
+
+        // Now signal a config change so that geo detection is disabled.
+        testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Now signal a config change so that geo detection is enabled. Only the primary can be
+        // enabled.
+        testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+    }
+
+    @Test
+    public void bothPermFailure_disableAndEnable() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        // Initialize and check initial state.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate a failure event from the primary. This will enable the secondary.
+        mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+        // Simulate failure event from the secondary.
+        mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
+                USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
         mTestCallback.assertUncertainSuggestionMadeAndCommit();
         assertFalse(controllerImpl.isUncertaintyTimeoutSet());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
new file mode 100644
index 0000000..9a668b9
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link DisplayAreaGroup} container.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:DisplayAreaGroupTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class DisplayAreaGroupTest extends WindowTestsBase {
+
+    private DisplayAreaGroup mDisplayAreaGroup;
+    private TaskDisplayArea mTaskDisplayArea;
+    private Task mStack;
+    private ActivityRecord mActivity;
+
+    @Before
+    public void setUp() {
+        mDisplayAreaGroup = new DisplayAreaGroup(
+                mWm, "DisplayAreaGroup", FEATURE_VENDOR_FIRST);
+        final TaskDisplayArea defaultTda = mDisplayContent.getDefaultTaskDisplayArea();
+        final WindowContainer parentDA = defaultTda.getParent();
+        parentDA.addChild(mDisplayAreaGroup, parentDA.mChildren.indexOf(defaultTda) + 1);
+        mTaskDisplayArea = new TaskDisplayArea(
+                mDisplayContent, mWm, "TDA1", FEATURE_VENDOR_FIRST + 1);
+        mDisplayAreaGroup.addChild(mTaskDisplayArea, POSITION_TOP);
+        mStack = mTaskDisplayArea.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        mActivity = new ActivityBuilder(mAtm).setCreateTask(true).setStack(mStack).build();
+        mDisplayContent.setLastFocusedTaskDisplayArea(mTaskDisplayArea);
+    }
+
+    @Test
+    public void testIsOrientationDifferentFromDisplay() {
+        // Display is portrait, DisplayAreaGroup inherits that
+        mDisplayContent.setBounds(0, 0, 600, 900);
+
+        assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isFalse();
+
+        // DisplayAreaGroup is landscape, different Display
+        mDisplayAreaGroup.setBounds(0, 0, 600, 450);
+
+        assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isTrue();
+
+        // DisplayAreaGroup is portrait, same as Display
+        mDisplayAreaGroup.setBounds(0, 0, 300, 900);
+
+        assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isFalse();
+    }
+
+    @Test
+    public void testGetOrientation() {
+        doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any(), any());
+        mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+        // Display is portrait, DisplayAreaGroup inherits that
+        mDisplayContent.setBounds(0, 0, 600, 900);
+
+        assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
+        assertThat(mActivity.getRequestedConfigurationOrientation())
+                .isEqualTo(ORIENTATION_PORTRAIT);
+
+        // DisplayAreaGroup is landscape, different from Display
+        mDisplayAreaGroup.setBounds(0, 0, 600, 450);
+
+        assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+        assertThat(mActivity.getRequestedConfigurationOrientation())
+                .isEqualTo(ORIENTATION_LANDSCAPE);
+
+        // DisplayAreaGroup is portrait, same as Display
+        mDisplayAreaGroup.setBounds(0, 0, 300, 900);
+
+        assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
+        assertThat(mActivity.getRequestedConfigurationOrientation())
+                .isEqualTo(ORIENTATION_PORTRAIT);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index f4f172d..7a30c37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1188,7 +1188,7 @@
                 () -> mAtm.unregisterTaskStackListener(null));
         assertSecurityException(expectCallable, () -> mAtm.getTaskDescription(0));
         assertSecurityException(expectCallable, () -> mAtm.cancelTaskWindowTransition(0));
-        assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, null,
+        assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, 0,
                 null));
         assertSecurityException(expectCallable, () -> mAtm.cancelRecentsAnimation(true));
         assertSecurityException(expectCallable, () -> mAtm.stopAppSwitches());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index d821d38..c10d4fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -147,7 +147,7 @@
 
         Intent recentsIntent = new Intent().setComponent(mRecentsComponent);
         // Null animation indicates to preload.
-        mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+        mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
                 null /* recentsAnimationRunner */);
 
         Task recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN,
@@ -167,7 +167,7 @@
 
         spyOn(recentsActivity);
         // Start when the recents activity exists. It should ensure the configuration.
-        mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+        mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
                 null /* recentsAnimationRunner */);
 
         verify(recentsActivity).ensureActivityConfiguration(anyInt() /* globalChanges */,
@@ -381,7 +381,7 @@
 
         Intent recentsIntent = new Intent();
         recentsIntent.setComponent(recentsComponent);
-        mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+        mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
                 mock(IRecentsAnimationRunner.class));
         return recentsAnimation[0];
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index d7eedd9..d0a5644 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -147,13 +147,6 @@
     }
 
     @Override
-    public SurfaceControl.Transaction deferTransactionUntilSurface(SurfaceControl sc,
-            Surface barrierSurface,
-            long frameNumber) {
-        return this;
-    }
-
-    @Override
     public SurfaceControl.Transaction reparentChildren(SurfaceControl sc,
             SurfaceControl newParent) {
         return this;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7b84385..12e56cc 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -85,8 +85,6 @@
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.aidl.IImsConfig;
-import android.telephony.ims.aidl.IImsMmTelFeature;
-import android.telephony.ims.aidl.IImsRcsFeature;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -94,7 +92,6 @@
 import android.util.Log;
 import android.util.Pair;
 
-import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CellNetworkScanResult;
@@ -7384,80 +7381,6 @@
     }
 
     /**
-     * Returns the {@link IImsMmTelFeature} that corresponds to the given slot Id and MMTel
-     * feature or {@link null} if the service is not available. If an MMTelFeature is available, the
-     * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates.
-     * @param slotIndex The SIM slot that we are requesting the {@link IImsMmTelFeature} for.
-     * @param callback Listener that will send updates to ImsManager when there are updates to
-     * ImsServiceController.
-     * @return {@link IImsMmTelFeature} interface for the feature specified or {@code null} if
-     * it is unavailable.
-     * @hide
-     */
-    public @Nullable IImsMmTelFeature getImsMmTelFeatureAndListen(int slotIndex,
-            IImsServiceFeatureCallback callback) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                return telephony.getMmTelFeatureAndListen(slotIndex, callback);
-            }
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "getImsMmTelFeatureAndListen, RemoteException: "
-                    + e.getMessage());
-        }
-        return null;
-    }
-
-    /**
-     * Returns the {@link IImsRcsFeature} that corresponds to the given slot Id and RCS
-     * feature for emergency calling or {@link null} if the service is not available. If an
-     * RcsFeature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
-     * listener for feature updates.
-     * @param slotIndex The SIM slot that we are requesting the {@link IImsRcsFeature} for.
-     * @param callback Listener that will send updates to ImsManager when there are updates to
-     * ImsServiceController.
-     * @return {@link IImsRcsFeature} interface for the feature specified or {@code null} if
-     * it is unavailable.
-     * @hide
-     */
-    public @Nullable IImsRcsFeature getImsRcsFeatureAndListen(int slotIndex,
-            IImsServiceFeatureCallback callback) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                return telephony.getRcsFeatureAndListen(slotIndex, callback);
-            }
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "getImsRcsFeatureAndListen, RemoteException: "
-                    + e.getMessage());
-        }
-        return null;
-    }
-
-    /**
-     * Unregister a IImsServiceFeatureCallback previously associated with an ImsFeature through
-     * {@link #getImsMmTelFeatureAndListen(int, IImsServiceFeatureCallback)} or
-     * {@link #getImsRcsFeatureAndListen(int, IImsServiceFeatureCallback)}.
-     * @param slotIndex The SIM slot associated with the callback.
-     * @param featureType The {@link android.telephony.ims.feature.ImsFeature.FeatureType}
-     *                    associated with the callback.
-     * @param callback The callback to be unregistered.
-     * @hide
-     */
-    public void unregisterImsFeatureCallback(int slotIndex, int featureType,
-            IImsServiceFeatureCallback callback) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                telephony.unregisterImsFeatureCallback(slotIndex, featureType, callback);
-            }
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "unregisterImsFeatureCallback, RemoteException: "
-                    + e.getMessage());
-        }
-    }
-
-    /**
      * @return the {@IImsRegistration} interface that corresponds with the slot index and feature.
      * @param slotIndex The SIM slot corresponding to the ImsService ImsRegistration is active for.
      * @param feature An integer indicating the feature that we wish to get the ImsRegistration for.
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index f6c14e6..ee2fce7 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -59,6 +59,7 @@
  * manager.
  */
 public class ImsMmTelManager implements RegistrationManager {
+    private static final String TAG = "ImsMmTelManager";
 
     /**
      * @hide
@@ -809,7 +810,7 @@
         }
 
         try {
-            getITelephony().isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
+            iTelephony.isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
                 @Override
                 public void accept(int result) {
                     executor.execute(() -> callback.accept(result == 1));
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index da7311c..8a05bdf 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims;
 
+import android.annotation.LongDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.Service;
@@ -41,6 +42,11 @@
 import com.android.ims.internal.IImsFeatureStatusCallback;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
  * ImsService must register the service in their AndroidManifest to be detected by the framework.
@@ -98,6 +104,32 @@
     private static final String LOG_TAG = "ImsService";
 
     /**
+     * This ImsService supports the capability to place emergency calls over MMTEL.
+     * @hide This is encoded into the {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, but we will be
+     * adding other capabilities in a central location, so track this capability here as well.
+     */
+    public static final long CAPABILITY_EMERGENCY_OVER_MMTEL = 1 << 0;
+
+    /**
+     * @hide
+     */
+    @LongDef(flag = true,
+            prefix = "CAPABILITY_",
+            value = {
+                    CAPABILITY_EMERGENCY_OVER_MMTEL
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImsServiceCapability {}
+
+    /**
+     * Used for logging purposes, see {@link #getCapabilitiesString(long)}
+     * @hide
+     */
+    private static final Map<Long, String> CAPABILITIES_LOG_MAP = new HashMap<Long, String>() {{
+            put(CAPABILITY_EMERGENCY_OVER_MMTEL, "EMERGENCY_OVER_MMTEL");
+        }};
+
+    /**
      * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
      * @hide
      */
@@ -409,4 +441,30 @@
     public ImsRegistrationImplBase getRegistration(int slotId) {
         return new ImsRegistrationImplBase();
     }
+
+    /**
+     * @return A string representation of the ImsService capabilties for logging.
+     * @hide
+     */
+    public static String getCapabilitiesString(@ImsServiceCapability long caps) {
+        StringBuffer result = new StringBuffer();
+        result.append("capabilities={ ");
+        // filter incrementally fills 0s from  left to right. This is used to keep filtering out
+        // more bits in the long until the remaining leftmost bits are all zero.
+        long filter = 0xFFFFFFFFFFFFFFFFL;
+        // position of iterator to potentially print capability.
+        long i = 0;
+        while ((caps & filter) != 0 && i <= 63) {
+            long bitToCheck = (1L << i);
+            if ((caps & bitToCheck) != 0) {
+                result.append(CAPABILITIES_LOG_MAP.getOrDefault(bitToCheck, bitToCheck + "?"));
+                result.append(" ");
+            }
+            // shift left by one and fill in another 1 on the leftmost bit.
+            filter <<= 1;
+            i++;
+        }
+        result.append("}");
+        return result.toString();
+    }
 }
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 9e46142..e01ea91 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -22,6 +22,8 @@
 import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 
+import com.android.ims.ImsFeatureContainer;
+import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.telephony.IIntegerConsumer;
 
 /**
@@ -50,4 +52,8 @@
     void setUceSettingEnabled(int subId, boolean isEnabled);
     void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c);
     void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c);
+
+    // Internal commands that should not be made public
+    void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback);
+    void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback);
 }
diff --git a/telephony/java/com/android/ims/ImsFeatureContainer.aidl b/telephony/java/com/android/ims/ImsFeatureContainer.aidl
new file mode 100644
index 0000000..9706f20
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsFeatureContainer.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+parcelable ImsFeatureContainer;
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/ImsFeatureContainer.java b/telephony/java/com/android/ims/ImsFeatureContainer.java
new file mode 100644
index 0000000..b259679
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsFeatureContainer.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.aidl.IImsRegistration;
+import android.telephony.ims.feature.ImsFeature;
+
+import java.util.Objects;
+
+/**
+ * Contains an IBinder linking to the appropriate ImsFeature as well as the associated
+ * interfaces.
+ * @hide
+ */
+public final class ImsFeatureContainer implements Parcelable {
+    /**
+     * ImsFeature that is being tracked.
+     */
+    public final IBinder imsFeature;
+
+    /**
+     * IImsConfig interface that should be associated with the ImsFeature.
+     */
+    public final android.telephony.ims.aidl.IImsConfig imsConfig;
+
+    /**
+     * IImsRegistration interface that should be associated with this ImsFeature.
+     */
+    public final IImsRegistration imsRegistration;
+
+    /**
+     * State of the feature that is being tracked.
+     */
+    private @ImsFeature.ImsState int mState = ImsFeature.STATE_UNAVAILABLE;
+
+    /**
+     * Capabilities of this ImsService.
+     */
+    private @ImsService.ImsServiceCapability long mCapabilities;
+    /**
+     * Contains the ImsFeature IBinder as well as the ImsService interfaces associated with
+     * that feature.
+     * @param iFace IBinder connection to the ImsFeature.
+     * @param iConfig IImsConfig interface associated with the ImsFeature.
+     * @param iReg IImsRegistration interface associated with the ImsFeature
+     * @param initialCaps The initial capabilities that the ImsService supports.
+     */
+    public ImsFeatureContainer(@NonNull IBinder iFace, @NonNull IImsConfig iConfig,
+            @NonNull IImsRegistration iReg, long initialCaps) {
+        imsFeature = iFace;
+        imsConfig = iConfig;
+        imsRegistration = iReg;
+        mCapabilities = initialCaps;
+    }
+
+    /**
+     * Create an ImsFeatureContainer from a Parcel.
+     */
+    private ImsFeatureContainer(Parcel in) {
+        imsFeature = in.readStrongBinder();
+        imsConfig = IImsConfig.Stub.asInterface(in.readStrongBinder());
+        imsRegistration = IImsRegistration.Stub.asInterface(in.readStrongBinder());
+        mState = in.readInt();
+        mCapabilities = in.readLong();
+    }
+
+    /**
+     * @return the capabilties that are associated with the ImsService that this ImsFeature
+     * belongs to.
+     */
+    public @ImsService.ImsServiceCapability long getCapabilities() {
+        return mCapabilities;
+    }
+
+    /**
+     * Update the capabilities that are associated with the ImsService that this ImsFeature
+     * belongs to.
+     */
+    public void setCapabilities(@ImsService.ImsServiceCapability long caps) {
+        mCapabilities = caps;
+    }
+
+    /**
+     * @return The state of the ImsFeature.
+     */
+    public @ImsFeature.ImsState int getState() {
+        return mState;
+    }
+
+    /**
+     * Set the state that is associated with the ImsService that this ImsFeature
+     * belongs to.
+     */
+    public void setState(@ImsFeature.ImsState int state) {
+        mState = state;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ImsFeatureContainer that = (ImsFeatureContainer) o;
+        return imsFeature.equals(that.imsFeature) &&
+                imsConfig.equals(that.imsConfig) &&
+                imsRegistration.equals(that.imsRegistration) &&
+                mState == that.getState() &&
+                mCapabilities == that.getCapabilities();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(imsFeature, imsConfig, imsRegistration, mState, mCapabilities);
+    }
+
+    @Override
+    public String toString() {
+        return "FeatureContainer{" +
+                "imsFeature=" + imsFeature +
+                ", imsConfig=" + imsConfig +
+                ", imsRegistration=" + imsRegistration +
+                ", state=" + ImsFeature.STATE_LOG_MAP.get(mState) +
+                ", capabilities = " + ImsService.getCapabilitiesString(mCapabilities) +
+                '}';
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(imsFeature);
+        dest.writeStrongInterface(imsConfig);
+        dest.writeStrongInterface(imsRegistration);
+        dest.writeInt(mState);
+        dest.writeLong(mCapabilities);
+    }
+
+
+    public static final Creator<ImsFeatureContainer> CREATOR = new Creator<ImsFeatureContainer>() {
+        @Override
+        public ImsFeatureContainer createFromParcel(Parcel source) {
+            return new ImsFeatureContainer(source);
+        }
+
+        @Override
+        public ImsFeatureContainer[] newArray(int size) {
+            return new ImsFeatureContainer[size];
+        }
+    };
+}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
index 9a9cf53..f5f67bd 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
@@ -16,13 +16,18 @@
 
 package com.android.ims.internal;
 
+import com.android.ims.ImsFeatureContainer;
 /**
- *  Interface from ImsResolver to ImsServiceProxy in ImsManager.
- * Callback to ImsManager when a feature changes in the ImsServiceController.
+ *  Interface from ImsResolver to FeatureConnections.
+ * Callback to FeatureConnections when a feature's status changes.
  * {@hide}
  */
 oneway interface IImsServiceFeatureCallback {
-    void imsFeatureCreated(int slotId, int feature);
-    void imsFeatureRemoved(int slotId, int feature);
-    void imsStatusChanged(int slotId, int feature, int status);
+    void imsFeatureCreated(in ImsFeatureContainer feature);
+    // Reason defined in FeatureConnector.UnavailableReason
+    void imsFeatureRemoved(int reason);
+    // Status defined in ImsFeature.ImsState.
+    void imsStatusChanged(int status);
+    //Capabilities defined in ImsService.ImsServiceCapability
+    void updateCapabilities(long capabilities);
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d67384c..53069a1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -829,22 +829,14 @@
      *  as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback
      *  interface.
      */
-    IImsMmTelFeature getMmTelFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
-
-    /**
-     *  Get IImsRcsFeature binder from ImsResolver that corresponds to the subId and RCS feature
-     *  as well as registering the RcsFeature for callbacks using the IImsServiceFeatureCallback
-     *  interface.
-     */
-    IImsRcsFeature getRcsFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
+    void registerMmTelFeatureCallback(int slotId, in IImsServiceFeatureCallback callback);
 
     /**
      * Unregister a callback that was previously registered through
-     * {@link #getMmTelFeatureAndListen} or {@link #getRcsFeatureAndListen}. This should always be
-     * called when the callback is no longer being used.
+     * {@link #registerMmTelFeatureCallback}. This should always be called when the callback is no
+     * longer being used.
      */
-    void unregisterImsFeatureCallback(int slotId, int featureType,
-            in IImsServiceFeatureCallback callback);
+    void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback);
 
     /**
     * Returns the IImsRegistration associated with the slot and feature specified.
diff --git a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
index cf2cb4a..57055f7 100644
--- a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
+++ b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.p2p.servicediscovery;
+package android.net.wifi.p2p.nsd;
 
 parcelable WifiP2pServiceInfo;
diff --git a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
index d5a1e8f..e4d28bb 100644
--- a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
+++ b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.p2p.servicediscovery;
+package android.net.wifi.p2p.nsd;
 
 parcelable WifiP2pServiceRequest;