Merge "Support standard extension frontend status" into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 207f4b5..f04df2f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9429,6 +9429,7 @@
     method public int getSignalStrength();
     method public int getSnr();
     method public int getSpectralInversion();
+    method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @NonNull public android.media.tv.tuner.frontend.StandardExt getStandardExt();
     method @NonNull public int[] getStreamIds();
     method public int getSymbolRate();
     method @IntRange(from=0, to=65535) public int getSystemId();
@@ -9483,6 +9484,7 @@
     field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
     field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
     field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa
+    field @FlaggedApi("android.media.tv.flags.tuner_w_apis") public static final int FRONTEND_STATUS_TYPE_STANDARD_EXT = 47; // 0x2f
     field public static final int FRONTEND_STATUS_TYPE_STREAM_IDS = 39; // 0x27
     field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7
     field public static final int FRONTEND_STATUS_TYPE_T2_SYSTEM_ID = 29; // 0x1d
@@ -9774,6 +9776,11 @@
     method public default void onUnlocked();
   }
 
+  @FlaggedApi("android.media.tv.flags.tuner_w_apis") public final class StandardExt {
+    method public int getDvbsStandardExt();
+    method public int getDvbtStandardExt();
+  }
+
 }
 
 package android.media.voice {
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index fd677ac..898a8bf 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -16,11 +16,13 @@
 
 package android.media.tv.tuner.frontend;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.media.tv.flags.Flags;
 import android.media.tv.tuner.Lnb;
 import android.media.tv.tuner.TunerVersionChecker;
 
@@ -61,7 +63,7 @@
             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})
+            FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS, FRONTEND_STATUS_TYPE_STANDARD_EXT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface FrontendStatusType {}
 
@@ -311,6 +313,13 @@
     public static final int FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO =
             android.hardware.tv.tuner.FrontendStatusType.ATSC3_ALL_PLP_INFO;
 
+    /**
+     * Standard extension.
+     */
+    @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
+    public static final int FRONTEND_STATUS_TYPE_STANDARD_EXT =
+            android.hardware.tv.tuner.FrontendStatusType.STANDARD_EXT;
+
     /** @hide */
     @IntDef(value = {
             AtscFrontendSettings.MODULATION_UNDEFINED,
@@ -558,6 +567,7 @@
     private Long mIptvPacketsReceived;
     private Integer mIptvWorstJitterMs;
     private Integer mIptvAverageJitterMs;
+    private StandardExt mStandardExt;
 
     // Constructed and fields set by JNI code.
     private FrontendStatus() {
@@ -1273,4 +1283,27 @@
         }
         return mIptvAverageJitterMs;
     }
+    /**
+     * Gets the standard extension.
+     *
+     * <p>The tuner standard DVB-T has the extension DVB-T2, and the standard DVB-S has the
+     * extensions DVB-S2 and DVB-S2X. This method returns the current standard extension within the
+     * same standard series. This frontend status is reported when the standard extension
+     * transitions to another during playback.
+     *
+     * <p>This query is supported only by Tuner HAL 4.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * @return The current standard extension.
+     */
+    @NonNull
+    @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
+    public StandardExt getStandardExt() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_4_0, "StandardExt status");
+        if (mStandardExt == null) {
+            throw new IllegalStateException("StandardExt status is empty");
+        }
+        return mStandardExt;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/StandardExt.java b/media/java/android/media/tv/tuner/frontend/StandardExt.java
new file mode 100644
index 0000000..4907272
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/StandardExt.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 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.FlaggedApi;
+import android.annotation.SystemApi;
+import android.hardware.tv.tuner.FrontendDvbsStandard;
+import android.hardware.tv.tuner.FrontendDvbtStandard;
+import android.media.tv.flags.Flags;
+
+/**
+ * Standard extension for the standard DVB-T and DVB-S series.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_TUNER_W_APIS)
+public final class StandardExt {
+    private final int mDvbsStandardExt;
+    private final int mDvbtStandardExt;
+
+    /**
+     * Private constructor called by JNI only.
+     */
+    private StandardExt(int dvbsStandardExt, int dvbtStandardExt) {
+        mDvbsStandardExt = dvbsStandardExt;
+        mDvbtStandardExt = dvbtStandardExt;
+    }
+
+    /**
+     * Gets the DVB-S standard extension within the DVB-S standard series.
+     *
+     * @return An integer representing the standard, such as
+     * {@link DvbsFrontendSettings#STANDARD_S}.
+     *
+     * @see android.media.tv.tuner.frontend.DvbsFrontendSettings
+     */
+    @DvbsFrontendSettings.Standard
+    public int getDvbsStandardExt() {
+        if (mDvbsStandardExt == FrontendDvbsStandard.UNDEFINED) {
+            throw new IllegalStateException("No DVB-S standard transition");
+        }
+        return mDvbsStandardExt;
+    }
+
+    /**
+     * Gets the DVB-T standard extension within the DVB-T standard series.
+     *
+     * @return An integer representing the standard, such as
+     * {@link DvbtFrontendSettings#STANDARD_T}.
+     *
+     * @see android.media.tv.tuner.frontend.DvbtFrontendSettings
+     */
+    @DvbtFrontendSettings.Standard
+    public int getDvbtStandardExt() {
+        if (mDvbtStandardExt == FrontendDvbtStandard.UNDEFINED) {
+            throw new IllegalStateException("No DVB-T standard transition");
+        }
+        return mDvbtStandardExt;
+    }
+}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 9e1e2c3..80ca4f2 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -144,6 +144,7 @@
 #include <aidl/android/hardware/tv/tuner/FrontendScanAtsc3PlpInfo.h>
 #include <aidl/android/hardware/tv/tuner/FrontendScanMessageStandard.h>
 #include <aidl/android/hardware/tv/tuner/FrontendSpectralInversion.h>
+#include <aidl/android/hardware/tv/tuner/FrontendStandardExt.h>
 #include <aidl/android/hardware/tv/tuner/FrontendStatus.h>
 #include <aidl/android/hardware/tv/tuner/FrontendStatusAtsc3PlpInfo.h>
 #include <aidl/android/hardware/tv/tuner/FrontendStatusType.h>
@@ -302,6 +303,7 @@
 using ::aidl::android::hardware::tv::tuner::FrontendScanAtsc3PlpInfo;
 using ::aidl::android::hardware::tv::tuner::FrontendScanMessageStandard;
 using ::aidl::android::hardware::tv::tuner::FrontendSpectralInversion;
+using ::aidl::android::hardware::tv::tuner::FrontendStandardExt;
 using ::aidl::android::hardware::tv::tuner::FrontendStatus;
 using ::aidl::android::hardware::tv::tuner::FrontendStatusAtsc3PlpInfo;
 using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
@@ -2937,6 +2939,33 @@
                 env->SetObjectField(statusObj, field, newIntegerObj.get());
                 break;
             }
+            case FrontendStatus::Tag::standardExt: {
+                jfieldID field = env->GetFieldID(clazz, "mStandardExt",
+                        "Landroid/media/tv/tuner/frontend/StandardExt;");
+                ScopedLocalRef standardExtClazz(env,
+                        env->FindClass("android/media/tv/tuner/frontend/StandardExt"));
+                jmethodID initStandardExt = env->GetMethodID(standardExtClazz.get(), "<init>",
+                        "(II)V");
+
+                jint dvbsStandardExt = static_cast<jint>(FrontendDvbsStandard::UNDEFINED);
+                jint dvbtStandardExt = static_cast<jint>(FrontendDvbtStandard::UNDEFINED);
+                FrontendStandardExt standardExt = s.get<FrontendStatus::Tag::standardExt>();
+                switch (standardExt.getTag()) {
+                    case FrontendStandardExt::Tag::dvbsStandardExt: {
+                        dvbsStandardExt = static_cast<jint>(standardExt
+                                .get<FrontendStandardExt::Tag::dvbsStandardExt>());
+                        break;
+                    }
+                    case FrontendStandardExt::Tag::dvbtStandardExt: {
+                        dvbtStandardExt = static_cast<jint>(standardExt
+                                .get<FrontendStandardExt::Tag::dvbtStandardExt>());
+                        break;
+                    }
+                }
+                ScopedLocalRef standardExtObj(env, env->NewObject(standardExtClazz.get(),
+                        initStandardExt, dvbsStandardExt, dvbtStandardExt));
+                env->SetObjectField(statusObj, field, standardExtObj.get());
+            }
         }
     }
     return statusObj;