Merge "Less confusing error message."
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index fab5b5f..ad406a1 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -158,17 +158,11 @@
     boolean mForceAllAppStandbyForSmallBattery;
 
     /**
-     * True if the forced app standby feature is enabled in settings
-     */
-    @GuardedBy("mLock")
-    boolean mForcedAppStandbyEnabled;
-
-    /**
      * A lock-free set of (uid, packageName) pairs in background restricted mode.
      *
      * <p>
-     * It's bascially shadowing the {@link #mRunAnyRestrictedPackages} together with
-     * the {@link #mForcedAppStandbyEnabled} - mutations on them would result in copy-on-write.
+     * It's basically shadowing the {@link #mRunAnyRestrictedPackages}, any mutations on it would
+     * result in copy-on-write.
      * </p>
      */
     volatile Set<Pair<Integer, String>> mBackgroundRestrictedUidPackages = Collections.emptySet();
@@ -200,10 +194,9 @@
         int TEMP_EXEMPTION_LIST_CHANGED = 5;
         int EXEMPTED_BUCKET_CHANGED = 6;
         int FORCE_ALL_CHANGED = 7;
-        int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
 
-        int IS_UID_ACTIVE_CACHED = 9;
-        int IS_UID_ACTIVE_RAW = 10;
+        int IS_UID_ACTIVE_CACHED = 8;
+        int IS_UID_ACTIVE_RAW = 9;
     }
 
     private final StatLogger mStatLogger = new StatLogger(new String[] {
@@ -215,7 +208,6 @@
             "TEMP_EXEMPTION_LIST_CHANGED",
             "EXEMPTED_BUCKET_CHANGED",
             "FORCE_ALL_CHANGED",
-            "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED",
 
             "IS_UID_ACTIVE_CACHED",
             "IS_UID_ACTIVE_RAW",
@@ -228,18 +220,10 @@
         }
 
         void register() {
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
-                    false, this);
-
             mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
         }
 
-        boolean isForcedAppStandbyEnabled() {
-            return injectGetGlobalSettingInt(Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
-        }
-
         boolean isForcedAppStandbyForSmallBatteryEnabled() {
             return injectGetGlobalSettingInt(
                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
@@ -247,21 +231,7 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) {
-                final boolean enabled = isForcedAppStandbyEnabled();
-                synchronized (mLock) {
-                    if (mForcedAppStandbyEnabled == enabled) {
-                        return;
-                    }
-                    mForcedAppStandbyEnabled = enabled;
-                    updateBackgroundRestrictedUidPackagesLocked();
-                    if (DEBUG) {
-                        Slog.d(TAG, "Forced app standby feature flag changed: "
-                                + mForcedAppStandbyEnabled);
-                    }
-                }
-                mHandler.notifyForcedAppStandbyFeatureFlagChanged();
-            } else if (Settings.Global.getUriFor(
+            if (Settings.Global.getUriFor(
                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
                 final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
                 synchronized (mLock) {
@@ -515,7 +485,6 @@
 
             mFlagsObserver = new FeatureFlagsObserver();
             mFlagsObserver.register();
-            mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled();
             mForceAllAppStandbyForSmallBattery =
                     mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
             mStandbyTracker = new StandbyTracker();
@@ -636,14 +605,10 @@
 
     /**
      * Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on
-     * {@link #mRunAnyRestrictedPackages} or {@link #mForcedAppStandbyEnabled}.
+     * {@link #mRunAnyRestrictedPackages}.
      */
     @GuardedBy("mLock")
     private void updateBackgroundRestrictedUidPackagesLocked() {
-        if (!mForcedAppStandbyEnabled) {
-            mBackgroundRestrictedUidPackages = Collections.emptySet();
-            return;
-        }
         Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
         for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
             fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
@@ -821,13 +786,14 @@
 
     private class MyHandler extends Handler {
         private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
+        // Unused ids 1, 2.
         private static final int MSG_RUN_ANY_CHANGED = 3;
         private static final int MSG_ALL_UNEXEMPTED = 4;
         private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5;
         private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6;
         private static final int MSG_FORCE_ALL_CHANGED = 7;
         private static final int MSG_USER_REMOVED = 8;
-        private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
+        // Unused id 9.
         private static final int MSG_EXEMPTED_BUCKET_CHANGED = 10;
         private static final int MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED = 11;
 
@@ -867,11 +833,6 @@
             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
         }
 
-        public void notifyForcedAppStandbyFeatureFlagChanged() {
-            removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED);
-            obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
-        }
-
         public void notifyExemptedBucketChanged() {
             removeMessages(MSG_EXEMPTED_BUCKET_CHANGED);
             obtainMessage(MSG_EXEMPTED_BUCKET_CHANGED).sendToTarget();
@@ -966,22 +927,6 @@
                     mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start);
                     return;
 
-                case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
-                    // Feature flag for forced app standby changed.
-                    final boolean unblockAlarms;
-                    synchronized (mLock) {
-                        unblockAlarms = !mForcedAppStandbyEnabled;
-                    }
-                    for (Listener l : cloneListeners()) {
-                        l.updateAllJobs();
-                        if (unblockAlarms) {
-                            l.unblockAllUnrestrictedAlarms();
-                        }
-                    }
-                    mStatLogger.logDurationStat(
-                            Stats.FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED, start);
-                    return;
-
                 case MSG_USER_REMOVED:
                     handleUserRemoved(msg.arg1);
                     return;
@@ -1164,8 +1109,7 @@
             // If apps will be put into restricted standby bucket automatically on user-forced
             // app standby, instead of blocking alarms completely, let the restricted standby bucket
             // policy take care of it.
-            return (mForcedAppStandbyEnabled
-                    && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
+            return (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
                     && isRunAnyRestrictedLocked(uid, packageName));
         }
     }
@@ -1210,8 +1154,7 @@
             // If apps will be put into restricted standby bucket automatically on user-forced
             // app standby, instead of blocking jobs completely, let the restricted standby bucket
             // policy take care of it.
-            if (mForcedAppStandbyEnabled
-                    && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
+            if (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
                     && isRunAnyRestrictedLocked(uid, packageName)) {
                 return true;
             }
@@ -1321,8 +1264,6 @@
             pw.println("Current AppStateTracker State:");
 
             pw.increaseIndent();
-            pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
-
             pw.print("Force all apps standby: ");
             pw.println(isForceAllAppsStandbyEnabled());
 
@@ -1400,8 +1341,6 @@
         synchronized (mLock) {
             final long token = proto.start(fieldId);
 
-            proto.write(AppStateTrackerProto.FORCED_APP_STANDBY_FEATURE_ENABLED,
-                    mForcedAppStandbyEnabled);
             proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY,
                     isForceAllAppsStandbyEnabled());
             proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index e41eb00..37d190d 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -5379,9 +5379,7 @@
 
         @Override
         public void unblockAllUnrestrictedAlarms() {
-            // Called when:
-            // 1. Power exemption list changes,
-            // 2. User FAS feature is disabled.
+            // Called when the power exemption list changes.
             synchronized (mLock) {
                 sendAllUnrestrictedPendingBackgroundAlarmsLocked();
             }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d99e151..50cafe8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8767,6 +8767,7 @@
     field public static final int TYPE_DVBC = 4; // 0x4
     field public static final int TYPE_DVBS = 5; // 0x5
     field public static final int TYPE_DVBT = 6; // 0x6
+    field public static final int TYPE_IPTV = 11; // 0xb
     field public static final int TYPE_ISDBS = 7; // 0x7
     field public static final int TYPE_ISDBS3 = 8; // 0x8
     field public static final int TYPE_ISDBT = 9; // 0x9
@@ -8789,6 +8790,11 @@
     method public int getHierarchy();
     method public long getInnerFec();
     method @NonNull public int[] getInterleaving();
+    method @IntRange(from=0) public int getIptvAverageJitterMillis();
+    method @NonNull public String getIptvContentUrl();
+    method @IntRange(from=0) public long getIptvPacketsLost();
+    method @IntRange(from=0) public long getIptvPacketsReceived();
+    method @IntRange(from=0) public int getIptvWorstJitterMillis();
     method public int getIsdbtMode();
     method public int getIsdbtPartialReceptionFlag();
     method @IntRange(from=0, to=255) @NonNull public int[] getIsdbtSegment();
@@ -8832,6 +8838,11 @@
     field public static final int FRONTEND_STATUS_TYPE_GUARD_INTERVAL = 26; // 0x1a
     field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13
     field public static final int FRONTEND_STATUS_TYPE_INTERLEAVINGS = 30; // 0x1e
+    field public static final int FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS = 46; // 0x2e
+    field public static final int FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL = 42; // 0x2a
+    field public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST = 43; // 0x2b
+    field public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED = 44; // 0x2c
+    field public static final int FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS = 45; // 0x2d
     field public static final int FRONTEND_STATUS_TYPE_ISDBT_MODE = 37; // 0x25
     field public static final int FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG = 38; // 0x26
     field public static final int FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS = 31; // 0x1f
@@ -8877,6 +8888,60 @@
     field public static final int FRONTEND_STATUS_READINESS_UNSUPPORTED = 4; // 0x4
   }
 
+  public class IptvFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
+    ctor public IptvFrontendSettings(@NonNull byte[], @NonNull byte[], int, int, @NonNull android.media.tv.tuner.frontend.IptvFrontendSettingsFec, int, int, long, @NonNull String);
+    method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettings.Builder builder();
+    method @IntRange(from=0) public long getBitrate();
+    method @NonNull public String getContentUrl();
+    method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
+    method public int getDstPort();
+    method @Nullable public android.media.tv.tuner.frontend.IptvFrontendSettingsFec getFec();
+    method public int getIgmp();
+    method public int getProtocol();
+    method @NonNull @Size(min=4, max=16) public byte[] getSrcIpAddress();
+    method public int getSrcPort();
+    method public int getType();
+    field public static final int IGMP_UNDEFINED = 0; // 0x0
+    field public static final int IGMP_V1 = 1; // 0x1
+    field public static final int IGMP_V2 = 2; // 0x2
+    field public static final int IGMP_V3 = 4; // 0x4
+    field public static final int PROTOCOL_RTP = 2; // 0x2
+    field public static final int PROTOCOL_UDP = 1; // 0x1
+    field public static final int PROTOCOL_UNDEFINED = 0; // 0x0
+  }
+
+  public static final class IptvFrontendSettings.Builder {
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings build();
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setBitrate(@IntRange(from=0) long);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setContentUrl(@NonNull String);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setDstIpAddress(@NonNull byte[]);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setDstPort(int);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setFec(@Nullable android.media.tv.tuner.frontend.IptvFrontendSettingsFec);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setIgmp(int);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setProtocol(int);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setSrcIpAddress(@NonNull byte[]);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setSrcPort(int);
+  }
+
+  public class IptvFrontendSettingsFec {
+    ctor public IptvFrontendSettingsFec(int, int, int);
+    method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder builder();
+    method @IntRange(from=0) public int getFecColNum();
+    method @IntRange(from=0) public int getFecRowNum();
+    method public int getFecType();
+    field public static final int FEC_TYPE_COLUMN = 1; // 0x1
+    field public static final int FEC_TYPE_COLUMN_ROW = 4; // 0x4
+    field public static final int FEC_TYPE_ROW = 2; // 0x2
+    field public static final int FEC_TYPE_UNDEFINED = 0; // 0x0
+  }
+
+  public static final class IptvFrontendSettingsFec.Builder {
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec build();
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecColNum(@IntRange(from=0) int);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecRowNum(@IntRange(from=0) int);
+    method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecType(int);
+  }
+
   public class Isdbs3FrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
     method public int getCodeRateCapability();
     method public int getModulationCapability();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 70d8e5d..9de424f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14568,15 +14568,6 @@
                 "app_auto_restriction_enabled";
 
         /**
-         * Feature flag to enable or disable the Forced App Standby feature.
-         * Type: int (0 for false, 1 for true)
-         * Default: 1
-         * @hide
-         */
-        @Readable
-        public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
-
-        /**
          * Whether or not to enable Forced App Standby on small battery devices.
          * Type: int (0 for false, 1 for true)
          * Default: 0
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 27c2a98..ac920d2 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -1170,6 +1170,11 @@
      * in Tuner 2.0 or higher version. Unsupported version will cause no-op. Use {@link
      * TunerVersionChecker#getTunerVersion()} to get the version information.
      *
+     * <p>Tuning with {@link
+     * android.media.tv.tuner.frontend.IptvFrontendSettings} is only supported
+     * in Tuner 3.0 or higher version. Unsupported version will cause no-op. Use {@link
+     * TunerVersionChecker#getTunerVersion()} to get the version information.
+     *
      * @param settings Signal delivery information the frontend uses to
      *                 search and lock the signal.
      * @return result status of tune operation.
@@ -1198,6 +1203,12 @@
                     return RESULT_UNAVAILABLE;
                 }
             }
+            if (mFrontendType == FrontendSettings.TYPE_IPTV) {
+                if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                        TunerVersionChecker.TUNER_VERSION_3_0, "Tuner with IPTV Frontend")) {
+                    return RESULT_UNAVAILABLE;
+                }
+            }
 
             if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND, mFrontendLock)) {
                 mFrontendInfo = null;
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 2f45a70..0a1ecee 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -38,7 +38,7 @@
     /** @hide */
     @IntDef(prefix = "TYPE_",
             value = {TYPE_UNDEFINED, TYPE_ANALOG, TYPE_ATSC, TYPE_ATSC3, TYPE_DVBC, TYPE_DVBS,
-                    TYPE_DVBT, TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT, TYPE_DTMB})
+                    TYPE_DVBT, TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT, TYPE_DTMB, TYPE_IPTV})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Type {}
 
@@ -86,7 +86,10 @@
      * Digital Terrestrial Multimedia Broadcast standard (DTMB) frontend type.
      */
     public static final int TYPE_DTMB = FrontendType.DTMB;
-
+    /**
+     * Internet Protocol (IPTV) frontend type.
+     */
+    public static final int TYPE_IPTV = FrontendType.IPTV;
 
     /** @hide */
     @LongDef(prefix = "FEC_",
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 9fbea72..fd677ac 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -23,6 +23,7 @@
 import android.annotation.SystemApi;
 import android.media.tv.tuner.Lnb;
 import android.media.tv.tuner.TunerVersionChecker;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
@@ -57,7 +58,10 @@
             FRONTEND_STATUS_TYPE_IS_MISO_ENABLED, FRONTEND_STATUS_TYPE_IS_LINEAR,
             FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES_ENABLED, FRONTEND_STATUS_TYPE_ISDBT_MODE,
             FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG, FRONTEND_STATUS_TYPE_STREAM_IDS,
-            FRONTEND_STATUS_TYPE_DVBT_CELL_IDS, FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO})
+            FRONTEND_STATUS_TYPE_DVBT_CELL_IDS, FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO,
+            FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL, FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST,
+            FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED, FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS,
+            FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS})
     @Retention(RetentionPolicy.SOURCE)
     public @interface FrontendStatusType {}
 
@@ -271,6 +275,36 @@
             android.hardware.tv.tuner.FrontendStatusType.DVBT_CELL_IDS;
 
     /**
+     * IPTV content URL.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL =
+            android.hardware.tv.tuner.FrontendStatusType.IPTV_CONTENT_URL;
+
+    /**
+     * IPTV packets lost.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST =
+            android.hardware.tv.tuner.FrontendStatusType.IPTV_PACKETS_LOST;
+
+    /**
+     * IPTV packets received.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED =
+            android.hardware.tv.tuner.FrontendStatusType.IPTV_PACKETS_RECEIVED;
+
+    /**
+     * IPTV worst jitter.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS =
+            android.hardware.tv.tuner.FrontendStatusType.IPTV_WORST_JITTER_MS;
+
+    /**
+     * IPTV average jitter.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS =
+            android.hardware.tv.tuner.FrontendStatusType.IPTV_AVERAGE_JITTER_MS;
+
+    /**
      * All PLP information in a frequency band for ATSC-3.0 frontend, which includes both tuned and
      * not tuned PLPs for currently watching service.
      */
@@ -519,6 +553,11 @@
     private int[] mStreamIds;
     private int[] mDvbtCellIds;
     private Atsc3PlpInfo[] mAllPlpInfo;
+    private String mIptvContentUrl;
+    private Long mIptvPacketsLost;
+    private Long mIptvPacketsReceived;
+    private Integer mIptvWorstJitterMs;
+    private Integer mIptvAverageJitterMs;
 
     // Constructed and fields set by JNI code.
     private FrontendStatus() {
@@ -1144,4 +1183,94 @@
             return mUec;
         }
     }
+
+    /**
+     * Gets the IPTV content URL.
+     *
+     * @return A String URL in the format protocol://ip:port (udp://127.0.0.1:3000).
+     *
+     * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @NonNull
+    public String getIptvContentUrl() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_3_0, "IptvContentUrl status");
+        if (mIptvContentUrl == null) {
+            throw new IllegalStateException("IptvContentUrl status is empty");
+        }
+        return mIptvContentUrl;
+    }
+
+    /**
+     * Gets the number of packets lost.
+     *
+     * @return A long value representing the number of packets lost in transmission.
+     *
+     * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @IntRange(from = 0)
+    public long getIptvPacketsLost() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_3_0, "IptvPacketsLost status");
+        if (mIptvPacketsLost == null) {
+            throw new IllegalStateException("IptvPacketsLost status is empty");
+        }
+        return mIptvPacketsLost;
+    }
+
+    /**
+     * Gets the number of packets received.
+     *
+     * @return A long value representing the number of packets received.
+     *
+     * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @IntRange(from = 0)
+    public long getIptvPacketsReceived() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_3_0, "IptvPacketsReceived status");
+        if (mIptvPacketsReceived == null) {
+            throw new IllegalStateException("IptvPacketsReceived status is empty");
+        }
+        return mIptvPacketsReceived;
+    }
+
+    /**
+     * Gets the worst jitter.
+     *
+     * @return An integer representing worst jitter recorded (in milliseconds).
+     *
+     * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @IntRange(from = 0)
+    public int getIptvWorstJitterMillis() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_3_0, "IptvWorstJitterMs status");
+        if (mIptvWorstJitterMs == null) {
+            throw new IllegalStateException("IptvWorstJitterMs status is empty");
+        }
+        return mIptvWorstJitterMs;
+    }
+
+    /**
+     * Gets the average jitter.
+     *
+     * @return An integer representing average jitter recorded (in milliseconds).
+     *
+     * <p>This query is only supported by Tuner HAL 3.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @IntRange(from = 0)
+    public int getIptvAverageJitterMillis() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_3_0, "IptvAverageJitterMs status");
+        if (mIptvAverageJitterMs == null) {
+            throw new IllegalStateException("IptvAverageJitterMs status is empty");
+        }
+        return mIptvAverageJitterMs;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java
new file mode 100644
index 0000000..fb11ea9
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2023 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.media.tv.tuner.frontend;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.Size;
+import android.annotation.SystemApi;
+import android.hardware.tv.tuner.FrontendIptvSettingsIgmp;
+import android.hardware.tv.tuner.FrontendIptvSettingsProtocol;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Frontend settings for IPTV.
+ *
+ * @hide
+ */
+@SystemApi
+public class IptvFrontendSettings extends FrontendSettings {
+    /** @hide */
+    @IntDef(prefix = "PROTOCOL_",
+            value = {PROTOCOL_UNDEFINED, PROTOCOL_UDP, PROTOCOL_RTP})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Protocol {}
+
+    /**
+     * IP protocol type UNDEFINED.
+     */
+    public static final int PROTOCOL_UNDEFINED = FrontendIptvSettingsProtocol.UNDEFINED;
+
+    /**
+     * IP protocol type UDP (User Datagram Protocol).
+     */
+    public static final int PROTOCOL_UDP = FrontendIptvSettingsProtocol.UDP;
+
+    /**
+     * IP protocol type RTP (Real-time Transport Protocol).
+     */
+    public static final int PROTOCOL_RTP = FrontendIptvSettingsProtocol.RTP;
+
+    /** @hide */
+    @IntDef(prefix = "IGMP_",
+            value = {IGMP_UNDEFINED, IGMP_V1, IGMP_V2, IGMP_V3})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Igmp {}
+
+    /**
+     * IGMP (Internet Group Management Protocol) UNDEFINED.
+     */
+    public static final int IGMP_UNDEFINED = FrontendIptvSettingsIgmp.UNDEFINED;
+
+    /**
+     * IGMP (Internet Group Management Protocol) V1.
+     */
+    public static final int IGMP_V1 = FrontendIptvSettingsIgmp.V1;
+
+    /**
+     * IGMP (Internet Group Management Protocol) V2.
+     */
+    public static final int IGMP_V2 = FrontendIptvSettingsIgmp.V2;
+
+    /**
+     * IGMP (Internet Group Management Protocol) V3.
+     */
+    public static final int IGMP_V3 = FrontendIptvSettingsIgmp.V3;
+
+    private final byte[] mSrcIpAddress;
+    private final byte[] mDstIpAddress;
+    private final int mSrcPort;
+    private final int mDstPort;
+    private final IptvFrontendSettingsFec mFec;
+    private final int mProtocol;
+    private final int mIgmp;
+    private final long mBitrate;
+    private final String mContentUrl;
+
+    public IptvFrontendSettings(@NonNull byte[] srcIpAddress, @NonNull byte[] dstIpAddress,
+            int srcPort, int dstPort, @NonNull IptvFrontendSettingsFec fec, int protocol, int igmp,
+            long bitrate, @NonNull String contentUrl) {
+        super(0);
+        mSrcIpAddress = srcIpAddress;
+        mDstIpAddress = dstIpAddress;
+        mSrcPort = srcPort;
+        mDstPort = dstPort;
+        mFec = fec;
+        mProtocol = protocol;
+        mIgmp = igmp;
+        mBitrate = bitrate;
+        mContentUrl = contentUrl;
+    }
+
+    /**
+     * Gets the source IP address.
+     */
+    @Size(min = 4, max = 16)
+    @NonNull
+    public byte[] getSrcIpAddress() {
+        return mSrcIpAddress;
+    }
+
+    /**
+     * Gets the destination IP address.
+     */
+    @Size(min = 4, max = 16)
+    @NonNull
+    public byte[] getDstIpAddress() {
+        return mDstIpAddress;
+    }
+
+    /**
+     * Gets the source port.
+     */
+    public int getSrcPort() {
+        return mSrcPort;
+    }
+
+    /**
+     * Gets the destination port.
+     */
+    public int getDstPort() {
+        return mDstPort;
+    }
+
+    /**
+     * Gets FEC (Forward Error Correction).
+     */
+    @Nullable
+    public IptvFrontendSettingsFec getFec() {
+        return mFec;
+    }
+
+    /**
+     * Gets the protocol.
+     */
+    @Protocol
+    public int getProtocol() {
+        return mProtocol;
+    }
+
+    /**
+     * Gets the IGMP (Internet Group Management Protocol).
+     */
+    @Igmp
+    public int getIgmp() {
+        return mIgmp;
+    }
+
+    /**
+     * Gets the bitrate.
+     */
+    @IntRange(from = 0)
+    public long getBitrate() {
+        return mBitrate;
+    }
+
+    /**
+     * Gets the contentUrl
+     * contentUrl is a source URL in the format protocol://ip:port containing data
+     */
+    @NonNull
+    public String getContentUrl() {
+        return mContentUrl;
+    }
+
+    /**
+     * Creates a builder for {@link IptvFrontendSettings}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link IptvFrontendSettings}.
+     */
+    public static final class Builder {
+        private byte[] mSrcIpAddress = {0, 0, 0, 0};
+        private byte[] mDstIpAddress = {0, 0, 0, 0};
+        private int mSrcPort = 0;
+        private int mDstPort = 0;
+        private IptvFrontendSettingsFec mFec = null;
+        private int mProtocol = FrontendIptvSettingsProtocol.UNDEFINED;
+        private int mIgmp = FrontendIptvSettingsIgmp.UNDEFINED;
+        private long mBitrate = 0;
+        private String mContentUrl = "";
+
+        private Builder() {
+        }
+
+        /**
+         * Sets the source IP address.
+         *
+         * <p>Default value is 0.0.0.0, an invalid IP address.
+         */
+        @NonNull
+        public Builder setSrcIpAddress(@NonNull  byte[] srcIpAddress) {
+            mSrcIpAddress = srcIpAddress;
+            return this;
+        }
+
+        /**
+         * Sets the destination IP address.
+         *
+         * <p>Default value is 0.0.0.0, an invalid IP address.
+         */
+        @NonNull
+        public Builder setDstIpAddress(@NonNull  byte[] dstIpAddress) {
+            mDstIpAddress = dstIpAddress;
+            return this;
+        }
+
+        /**
+         * Sets the source IP port.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        public Builder setSrcPort(int srcPort) {
+            mSrcPort = srcPort;
+            return this;
+        }
+
+        /**
+         * Sets the destination IP port.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        public Builder setDstPort(int dstPort) {
+            mDstPort = dstPort;
+            return this;
+        }
+
+        /**
+         * Sets the FEC (Forward Error Correction).
+         *
+         * <p>Default value is {@code null}.
+         */
+        @NonNull
+        public Builder setFec(@Nullable IptvFrontendSettingsFec fec) {
+            mFec = fec;
+            return this;
+        }
+
+        /**
+         * Sets the protocol.
+         *
+         * <p>Default value is {@link #PROTOCOL_UNDEFINED}.
+         */
+        @NonNull
+        public Builder setProtocol(@Protocol int protocol) {
+            mProtocol = protocol;
+            return this;
+        }
+
+        /**
+         * Sets the IGMP (Internet Group Management Protocol).
+         *
+         * <p>Default value is {@link #IGMP_UNDEFINED}.
+         */
+        @NonNull
+        public Builder setIgmp(@Igmp int igmp) {
+            mIgmp = igmp;
+            return this;
+        }
+
+        /**
+         * Sets the bitrate.
+         *
+         * <p>Default value is 0.
+         */
+        @NonNull
+        public Builder setBitrate(@IntRange(from = 0) long bitrate) {
+            mBitrate = bitrate;
+            return this;
+        }
+
+        /**
+         * Sets the contentUrl.
+         *
+         * <p>Default value is "".
+         */
+        @NonNull
+        public Builder setContentUrl(@NonNull String contentUrl) {
+            mContentUrl = contentUrl;
+            return this;
+        }
+
+        /**
+         * Builds a {@link IptvFrontendSettings} object.
+         */
+        @NonNull
+        public IptvFrontendSettings build() {
+            return new IptvFrontendSettings(mSrcIpAddress, mDstIpAddress, mSrcPort,
+                    mDstPort, mFec, mProtocol, mIgmp, mBitrate, mContentUrl);
+        }
+    }
+
+    @Override
+    public int getType() {
+        return FrontendSettings.TYPE_IPTV;
+    }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java
new file mode 100644
index 0000000..699d615
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2023 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.media.tv.tuner.frontend;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.hardware.tv.tuner.FrontendIptvSettingsFecType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * FEC (Forward Error Correction) for IPTV.
+ *
+ * @hide
+ */
+@SystemApi
+public class IptvFrontendSettingsFec {
+    /** @hide */
+    @IntDef(prefix = "FEC_TYPE_",
+            value = {FEC_TYPE_UNDEFINED, FEC_TYPE_COLUMN, FEC_TYPE_ROW, FEC_TYPE_COLUMN_ROW})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FecType {}
+
+    /**
+     * FEC (Forward Error Correction) type UNDEFINED.
+     */
+    public static final int FEC_TYPE_UNDEFINED = FrontendIptvSettingsFecType.UNDEFINED;
+
+    /**
+     * FEC (Forward Error Correction) type Column.
+     */
+    public static final int FEC_TYPE_COLUMN = FrontendIptvSettingsFecType.COLUMN;
+
+    /**
+     * FEC (Forward Error Correction) type ROW.
+     */
+    public static final int FEC_TYPE_ROW = FrontendIptvSettingsFecType.ROW;
+
+    /**
+     * FEC (Forward Error Correction) type Column Row.
+     */
+    public static final int FEC_TYPE_COLUMN_ROW = FrontendIptvSettingsFecType.COLUMN_ROW;
+
+    private final int mFecType;
+    private final int mFecRowNum;
+    private final int mFecColNum;
+
+    public IptvFrontendSettingsFec(@FecType int fecType, int fecRowNum, int fecColNum) {
+        mFecType = fecType;
+        mFecRowNum = fecRowNum;
+        mFecColNum = fecColNum;
+    }
+
+    /**
+     * Gets the FEC (Forward Error Correction) type.
+     */
+    @FecType
+    public int getFecType() {
+        return mFecType;
+    }
+
+    /**
+     * Get the FEC (Forward Error Correction) row number.
+     */
+    @IntRange(from = 0)
+    public int getFecRowNum() {
+        return mFecRowNum;
+    }
+
+    /**
+     * Gets the FEC (Forward Error Correction) column number.
+     */
+    @IntRange(from = 0)
+    public int getFecColNum() {
+        return mFecColNum;
+    }
+
+    /**
+     * Creates a builder for {@link IptvFrontendSettingsFec}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link IptvFrontendSettingsFec}.
+     */
+    public static final class Builder {
+        private int mFecType;
+        private int mFecRowNum;
+        private int mFecColNum;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets the FEC (Forward Error Correction) type
+         */
+        @NonNull
+        public Builder setFecType(@FecType int fecType) {
+            mFecType = fecType;
+            return this;
+        }
+        /**
+         * Sets the FEC (Forward Error Correction) row number.
+         */
+        @NonNull
+        public Builder setFecRowNum(@IntRange(from = 0) int fecRowNum) {
+            mFecRowNum = fecRowNum;
+            return this;
+        }
+        /**
+         * Sets the FEC (Forward Error Correction) column number.
+         */
+        @NonNull
+        public Builder setFecColNum(@IntRange(from = 0) int fecColNum) {
+            mFecColNum = fecColNum;
+            return this;
+        }
+
+        /**
+         * Builds a {@link IptvFrontendSettingsFec} object.
+         */
+        @NonNull
+        public IptvFrontendSettingsFec build() {
+            return new IptvFrontendSettingsFec(mFecType, mFecRowNum, mFecColNum);
+        }
+    }
+}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 1a41bc2..35ee3ee9 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -2827,6 +2827,52 @@
                 env->DeleteLocalRef(plpClazz);
                 break;
             }
+            case FrontendStatus::Tag::iptvContentUrl: {
+                jfieldID field = env->GetFieldID(clazz, "mIptvContentUrl", "Ljava/lang/String;");
+                std::string iptvContentUrl = s.get<FrontendStatus::Tag::iptvContentUrl>();
+                jstring iptvContentUrlUtf8 = env->NewStringUTF(iptvContentUrl.c_str());
+                env->SetObjectField(statusObj, field, iptvContentUrlUtf8);
+                env->DeleteLocalRef(iptvContentUrlUtf8);
+                break;
+            }
+            case FrontendStatus::Tag::iptvPacketsLost: {
+                jfieldID field = env->GetFieldID(clazz, "mIptvPacketsLost", "Ljava/lang/Long;");
+                jobject newLongObj =
+                        env->NewObject(longClazz, initLong,
+                                       s.get<FrontendStatus::Tag::iptvPacketsLost>());
+                env->SetObjectField(statusObj, field, newLongObj);
+                env->DeleteLocalRef(newLongObj);
+                break;
+            }
+            case FrontendStatus::Tag::iptvPacketsReceived: {
+                jfieldID field = env->GetFieldID(clazz, "mIptvPacketsReceived", "Ljava/lang/Long;");
+                jobject newLongObj =
+                        env->NewObject(longClazz, initLong,
+                                       s.get<FrontendStatus::Tag::iptvPacketsReceived>());
+                env->SetObjectField(statusObj, field, newLongObj);
+                env->DeleteLocalRef(newLongObj);
+                break;
+            }
+            case FrontendStatus::Tag::iptvWorstJitterMs: {
+                jfieldID field = env->GetFieldID(clazz, "mIptvWorstJitterMs",
+                                                 "Ljava/lang/Integer;");
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       s.get<FrontendStatus::Tag::iptvWorstJitterMs>());
+                env->SetObjectField(statusObj, field, newIntegerObj);
+                env->DeleteLocalRef(newIntegerObj);
+                break;
+            }
+            case FrontendStatus::Tag::iptvAverageJitterMs: {
+                jfieldID field = env->GetFieldID(clazz, "mIptvAverageJitterMs",
+                                                 "Ljava/lang/Integer;");
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       s.get<FrontendStatus::Tag::iptvAverageJitterMs>());
+                env->SetObjectField(statusObj, field, newIntegerObj);
+                env->DeleteLocalRef(newIntegerObj);
+                break;
+            }
         }
     }
     return statusObj;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ede69be..75d28d5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -228,9 +228,6 @@
                 Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
                 GlobalSettingsProto.App.AUTO_RESTRICTION_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.FORCED_APP_STANDBY_ENABLED,
-                GlobalSettingsProto.App.FORCED_APP_STANDBY_ENABLED);
-        dumpSetting(s, p,
                 Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
                 GlobalSettingsProto.App.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED);
         p.end(appToken);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index db7032e..01740319 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -285,7 +285,6 @@
                     Settings.Global.FANCY_IME_ANIMATIONS,
                     Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
-                    Settings.Global.FORCED_APP_STANDBY_ENABLED,
                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
                     Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED,
                     Settings.Global.FSTRIM_MANDATORY_INTERVAL,
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index b76de5a..e182a6a 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,6 +24,7 @@
     android:orientation="vertical">
 
     <LinearLayout
+        android:id="@+id/media_metadata_section"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="start|center_vertical"
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index a9e1a4d..4803371 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -95,6 +95,7 @@
     private RecyclerView mDevicesRecyclerView;
     private LinearLayout mDeviceListLayout;
     private LinearLayout mCastAppLayout;
+    private LinearLayout mMediaMetadataSectionLayout;
     private Button mDoneButton;
     private Button mStopButton;
     private Button mAppButton;
@@ -240,6 +241,7 @@
         mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
         mHeaderIcon = mDialogView.requireViewById(R.id.header_icon);
         mDevicesRecyclerView = mDialogView.requireViewById(R.id.list_result);
+        mMediaMetadataSectionLayout = mDialogView.requireViewById(R.id.media_metadata_section);
         mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
         mDoneButton = mDialogView.requireViewById(R.id.done);
         mStopButton = mDialogView.requireViewById(R.id.stop);
@@ -255,21 +257,17 @@
         mDevicesRecyclerView.setLayoutManager(mLayoutManager);
         mDevicesRecyclerView.setAdapter(mAdapter);
         mDevicesRecyclerView.setHasFixedSize(false);
-        // Init header icon
-        mHeaderIcon.setOnClickListener(v -> onHeaderIconClick());
         // Init bottom buttons
         mDoneButton.setOnClickListener(v -> dismiss());
         mStopButton.setOnClickListener(v -> {
             mMediaOutputController.releaseSession();
             dismiss();
         });
-        mAppButton.setOnClickListener(v -> {
-            mBroadcastSender.closeSystemDialogs();
-            if (mMediaOutputController.getAppLaunchIntent() != null) {
-                mContext.startActivity(mMediaOutputController.getAppLaunchIntent());
-            }
-            dismiss();
-        });
+        mAppButton.setOnClickListener(v -> mMediaOutputController.tryToLaunchMediaApplication());
+        if (mMediaOutputController.isAdvancedLayoutSupported()) {
+            mMediaMetadataSectionLayout.setOnClickListener(
+                    v -> mMediaOutputController.tryToLaunchMediaApplication());
+        }
     }
 
     @Override
@@ -560,7 +558,7 @@
 
     @Override
     public void dismissDialog() {
-        dismiss();
+        mBroadcastSender.closeSystemDialogs();
     }
 
     void onHeaderIconClick() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 9cf672b..1587e62 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -382,6 +382,15 @@
         return mContext.getPackageManager().getLaunchIntentForPackage(mPackageName);
     }
 
+    void tryToLaunchMediaApplication() {
+        Intent launchIntent = getAppLaunchIntent();
+        if (launchIntent != null) {
+            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mCallback.dismissDialog();
+            mContext.startActivity(launchIntent);
+        }
+    }
+
     CharSequence getHeaderTitle() {
         if (mMediaController != null) {
             final MediaMetadata metadata = mMediaController.getMetadata();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 094d69a..9a0bd9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -243,6 +243,13 @@
     }
 
     @Test
+    public void dismissDialog_closesDialogByBroadcastSender() {
+        mMediaOutputBaseDialogImpl.dismissDialog();
+
+        verify(mBroadcastSender).closeSystemDialogs();
+    }
+
+    @Test
     public void whenBroadcasting_verifyLeBroadcastServiceCallBackIsRegisteredAndUnregistered() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index f5432e2..117751c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -252,6 +252,13 @@
     }
 
     @Test
+    public void tryToLaunchMediaApplication_nullIntent_skip() {
+        mMediaOutputController.tryToLaunchMediaApplication();
+
+        verify(mCb, never()).dismissDialog();
+    }
+
+    @Test
     public void onDevicesUpdated_unregistersNearbyDevicesCallback() throws RemoteException {
         mMediaOutputController.start(mCb);
 
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index f2e03aa..e871fc5 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -37,7 +37,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -165,18 +164,6 @@
                 awaitJobStart(DEFAULT_WAIT_TIMEOUT));
     }
 
-    @FlakyTest
-    @Test
-    public void testFeatureFlag() throws Exception {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.FORCED_APP_STANDBY_ENABLED, 0);
-        scheduleAndAssertJobStarted();
-        setAppOpsModeAllowed(false);
-        mIActivityManager.makePackageIdle(TEST_APP_PACKAGE, UserHandle.USER_CURRENT);
-        assertFalse("Job stopped even when feature flag was disabled",
-                awaitJobStop(DEFAULT_WAIT_TIMEOUT, JobParameters.STOP_REASON_UNDEFINED));
-    }
-
     @After
     public void tearDown() throws Exception {
         final Intent cancelJobsIntent = new Intent(TestJobActivity.ACTION_CANCEL_JOBS);
@@ -187,8 +174,6 @@
         Thread.sleep(500); // To avoid race with register in the next setUp
         setAppOpsModeAllowed(true);
         setPowerExemption(false);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.FORCED_APP_STANDBY_ENABLED, 1);
     }
 
     private void setPowerExemption(boolean exempt) throws RemoteException {