Add new features to tuner.

*) Support scan unlock event
*) Support get frontend hardware info.
*) Add scIndexMask to MediaEvent.
*) Support more AAC formats.
*) Move Lna to ITuner.

Bug: 203389496
Bug: 184017033
Bug: 202978951
Bug: 205265630
Bug: 203623028
Test: atest android.media.tv.tuner.cts on AIDL and HILD HALs.
Change-Id: Id1bf4f13e7afb5f4264bfc67ca7d822848c6e803
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a33d0a2..33deeb8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6382,6 +6382,7 @@
     method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
     method public long getAvSyncTime(int);
     method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getAvailableFrontendInfos();
+    method @Nullable public String getCurrentFrontendHardwardInfo();
     method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
     method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
     method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
@@ -6546,6 +6547,10 @@
     method public boolean isPassthrough();
     method public boolean useSecureMemory();
     field public static final int AUDIO_STREAM_TYPE_AAC = 6; // 0x6
+    field public static final int AUDIO_STREAM_TYPE_AAC_ADTS = 16; // 0x10
+    field public static final int AUDIO_STREAM_TYPE_AAC_HE_ADTS = 18; // 0x12
+    field public static final int AUDIO_STREAM_TYPE_AAC_HE_LATM = 19; // 0x13
+    field public static final int AUDIO_STREAM_TYPE_AAC_LATM = 17; // 0x11
     field public static final int AUDIO_STREAM_TYPE_AC3 = 7; // 0x7
     field public static final int AUDIO_STREAM_TYPE_AC4 = 9; // 0x9
     field public static final int AUDIO_STREAM_TYPE_DRA = 15; // 0xf
@@ -6707,6 +6712,7 @@
     method @IntRange(from=0) public int getMpuSequenceNumber();
     method public long getOffset();
     method public long getPts();
+    method public int getScIndexMask();
     method public int getStreamId();
     method public boolean isDtsPresent();
     method public boolean isPrivateData();
@@ -7819,6 +7825,7 @@
     method public void onScanStopped();
     method public void onSignalTypeReported(int);
     method public void onSymbolRatesReported(@NonNull int[]);
+    method public default void onUnLocked();
   }
 
 }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 255b391b..97fe1b1 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -687,6 +687,7 @@
     private native FrontendInfo nativeGetFrontendInfo(int id);
     private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
     private native TimeFilter nativeOpenTimeFilter();
+    private native String nativeGetFrontendHardwareInfo();
 
     private native Lnb nativeOpenLnbByHandle(int handle);
     private native Lnb nativeOpenLnbByName(String name);
@@ -1278,6 +1279,34 @@
         return Arrays.asList(feInfoList);
     }
 
+    /**
+     * Gets the currently initialized and activated frontend hardware information. The return values
+     * would differ per device makers. E.g. RF chip version, Demod chip version, detailed status of
+     * dvbs blind scan, etc
+     *
+     * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+     * {@code null}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * @return The active frontend hardware information. {@code null} if the operation failed.
+     * @throws IllegalStateException if there is no active frontend currently.
+     */
+    @Nullable
+    public String getCurrentFrontendHardwardInfo() {
+        mFrontendLock.lock();
+        try {
+            if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                        TunerVersionChecker.TUNER_VERSION_2_0, "Get Frontend hardware info")) {
+                return null;
+            }
+            if (mFrontend == null) {
+                throw new IllegalStateException("frontend is not initialized");
+            }
+            return nativeGetFrontendHardwareInfo();
+        } finally {
+            mFrontendLock.unlock();
+        }
+    }
+
     /** @hide */
     public FrontendInfo getFrontendInfoById(int id) {
         mFrontendLock.lock();
@@ -1353,6 +1382,24 @@
         }
     }
 
+    private void onUnLocked() {
+        Log.d(TAG, "Wrote Stats Log for unlocked event from scanning.");
+        FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+                FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
+
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onUnLocked();
+                        }
+                    }
+                });
+            }
+        }
+    }
+
     private void onScanStopped() {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index ed04754..15811d2 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -107,7 +107,8 @@
                     AUDIO_STREAM_TYPE_AAC, AUDIO_STREAM_TYPE_AC3, AUDIO_STREAM_TYPE_EAC3,
                     AUDIO_STREAM_TYPE_AC4, AUDIO_STREAM_TYPE_DTS, AUDIO_STREAM_TYPE_DTS_HD,
                     AUDIO_STREAM_TYPE_WMA, AUDIO_STREAM_TYPE_OPUS, AUDIO_STREAM_TYPE_VORBIS,
-                    AUDIO_STREAM_TYPE_DRA})
+                    AUDIO_STREAM_TYPE_DRA, AUDIO_STREAM_TYPE_AAC_ADTS, AUDIO_STREAM_TYPE_AAC_LATM,
+                    AUDIO_STREAM_TYPE_AAC_HE_ADTS, AUDIO_STREAM_TYPE_AAC_HE_LATM})
     @Retention(RetentionPolicy.SOURCE)
     public @interface AudioStreamType {}
 
@@ -182,6 +183,41 @@
      */
     public static final int AUDIO_STREAM_TYPE_DRA = android.hardware.tv.tuner.AudioStreamType.DRA;
 
+    /*
+     * AAC with ADTS (Audio Data Transport Format).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_ADTS =
+            android.hardware.tv.tuner.AudioStreamType.AAC_ADTS;
+
+    /*
+     * AAC with ADTS with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_LATM =
+            android.hardware.tv.tuner.AudioStreamType.AAC_LATM;
+
+    /*
+     * High-Efficiency AAC (HE-AAC) with ADTS (Audio Data Transport Format).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_HE_ADTS =
+            android.hardware.tv.tuner.AudioStreamType.AAC_HE_ADTS;
+
+    /*
+     * High-Efficiency AAC (HE-AAC) with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+     *
+     * This API is only supported by Tuner HAL 2.0 or higher. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    public static final int AUDIO_STREAM_TYPE_AAC_HE_LATM =
+            android.hardware.tv.tuner.AudioStreamType.AAC_HE_LATM;
 
     private final boolean mIsPassthrough;
     private int mAudioStreamType = AUDIO_STREAM_TYPE_UNDEFINED;
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 79d4062..d958db1 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -49,12 +49,14 @@
     private final long mDataId;
     private final int mMpuSequenceNumber;
     private final boolean mIsPrivateData;
+    private final int mScIndexMask;
     private final AudioDescriptor mExtraMetaData;
 
     // This constructor is used by JNI code only
     private MediaEvent(int streamId, boolean isPtsPresent, long pts, boolean isDtsPresent, long dts,
             long dataLength, long offset, LinearBlock buffer, boolean isSecureMemory, long dataId,
-            int mpuSequenceNumber, boolean isPrivateData, AudioDescriptor extraMetaData) {
+            int mpuSequenceNumber, boolean isPrivateData, int scIndexMask,
+            AudioDescriptor extraMetaData) {
         mStreamId = streamId;
         mIsPtsPresent = isPtsPresent;
         mPts = pts;
@@ -67,6 +69,7 @@
         mDataId = dataId;
         mMpuSequenceNumber = mpuSequenceNumber;
         mIsPrivateData = isPrivateData;
+        mScIndexMask = scIndexMask;
         mExtraMetaData = extraMetaData;
     }
 
@@ -194,6 +197,17 @@
     }
 
     /**
+     * Gets SC (Start Code) index mask.
+     *
+     * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+     * {@code 0}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     */
+    @RecordSettings.ScIndexMask
+    public int getScIndexMask() {
+        return mScIndexMask;
+    }
+
+    /**
      * Gets audio extra metadata.
      */
     @Nullable
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index f61bd52..39406f5 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -31,6 +31,9 @@
     /** Scan locked the signal. */
     void onLocked();
 
+    /** Scan unlocked the signal. */
+    default void onUnLocked() {}
+
     /** Scan stopped. */
     void onScanStopped();
 
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index e91e238..a8e3288 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -604,9 +604,11 @@
                                              const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
-    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>",
-                                           "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;"
-                                           "ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
+    jmethodID eventInit = env->GetMethodID(
+            eventClazz,
+            "<init>",
+            "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;"
+            "ZJIZILandroid/media/tv/tuner/filter/AudioDescriptor;)V");
     jfieldID eventContext = env->GetFieldID(eventClazz, "mNativeContext", "J");
 
     const DemuxFilterMediaEvent &mediaEvent = event.get<DemuxFilterEvent::Tag::media>();
@@ -639,10 +641,20 @@
     jlong avDataId = mediaEvent.avDataId;
     jint mpuSequenceNumber = mediaEvent.mpuSequenceNumber;
     jboolean isPesPrivateData = mediaEvent.isPesPrivateData;
+    jint sc = 0;
+    if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scIndex) {
+        sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scIndex>();
+    } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scHevc) {
+        sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scHevc>();
+    } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scAvc) {
+        sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scAvc>();
+        // Java uses the values defined by HIDL HAL. Left shift 4 bits.
+        sc = sc << 4;
+    }
 
     jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, isDtsPresent,
                                  dts, dataLength, offset, nullptr, isSecureMemory, avDataId,
-                                 mpuSequenceNumber, isPesPrivateData, audioDescriptor);
+                                 mpuSequenceNumber, isPesPrivateData, sc, audioDescriptor);
 
     uint64_t avSharedMemSize = mFilterClient->getAvSharedHandleInfo().size;
     if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0 ||
@@ -1025,6 +1037,10 @@
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onLocked", "()V"));
+            } else {
+                env->CallVoidMethod(
+                        frontend,
+                        env->GetMethodID(clazz, "onUnLocked", "()V"));
             }
             break;
         }
@@ -1540,6 +1556,15 @@
                           maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps);
 }
 
+Result JTuner::getFrontendHardwareInfo(string &info) {
+    if (mFeClient == nullptr) {
+        ALOGE("frontend is not initialized");
+        return Result::INVALID_STATE;
+    }
+
+    return mFeClient->getHardwareInfo(info);
+}
+
 jobject JTuner::openLnbByHandle(int handle) {
     if (mTunerClient == nullptr) {
         return nullptr;
@@ -1649,11 +1674,10 @@
 }
 
 int JTuner::setLna(bool enable) {
-    if (mFeClient == nullptr) {
-        ALOGE("frontend client is not initialized");
-        return (int)Result::INVALID_STATE;
+    if (mTunerClient == nullptr) {
+        return (int)Result::NOT_INITIALIZED;
     }
-    Result result = mFeClient->setLna(enable);
+    Result result = mTunerClient->setLna(enable);
     return (int)result;
 }
 
@@ -4195,6 +4219,16 @@
     return filterObj;
 }
 
+static jstring android_media_tv_Tuner_get_frontend_hardware_info(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    string info;
+    Result r = tuner->getFrontendHardwareInfo(info);
+    if (r != Result::SUCCESS) {
+        return nullptr;
+    }
+    return env->NewStringUTF(info.data());
+}
+
 static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->closeFrontend();
@@ -4504,6 +4538,8 @@
     { "nativeOpenSharedFilter",
             "(Ljava/lang/String;)Landroid/media/tv/tuner/filter/SharedFilter;",
             (void *)android_media_tv_Tuner_open_shared_filter},
+    { "nativeGetFrontendHardwareInfo","()Ljava/lang/String;",
+            (void *)android_media_tv_Tuner_get_frontend_hardware_info },
 };
 
 static const JNINativeMethod gFilterMethods[] = {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 06e2492..4cad92b 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -200,6 +200,7 @@
     jint close();
     jint closeFrontend();
     jint closeDemux();
+    Result getFrontendHardwareInfo(string& info);
 
     jweak getObject();
 
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index 70309a0..0fdd8d8 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -102,15 +102,6 @@
     return Result::INVALID_STATE;
 }
 
-Result FrontendClient::setLna(bool bEnable) {
-    if (mTunerFrontend != nullptr) {
-        Status s = mTunerFrontend->setLna(bEnable);
-        return ClientHelper::getServiceSpecificErrorCode(s);
-    }
-
-    return Result::INVALID_STATE;
-}
-
 int32_t FrontendClient::linkCiCamToFrontend(int32_t ciCamId) {
     int32_t ltsId = static_cast<int32_t>(Constant::INVALID_LTS_ID);
 
@@ -143,6 +134,15 @@
     return Result::INVALID_STATE;
 }
 
+Result FrontendClient::getHardwareInfo(string& info) {
+    if (mTunerFrontend != nullptr) {
+        Status s = mTunerFrontend->getHardwareInfo(&info);
+        return ClientHelper::getServiceSpecificErrorCode(s);
+    }
+
+    return Result::INVALID_STATE;
+}
+
 shared_ptr<ITunerFrontend> FrontendClient::getAidlFrontend() {
     return mTunerFrontend;
 }
diff --git a/media/jni/tuner/FrontendClient.h b/media/jni/tuner/FrontendClient.h
index 08c0b20..77d9098 100644
--- a/media/jni/tuner/FrontendClient.h
+++ b/media/jni/tuner/FrontendClient.h
@@ -99,11 +99,6 @@
     Result setLnb(sp<LnbClient> lnbClient);
 
     /**
-     * Enable or Disable Low Noise Amplifier (LNA).
-     */
-    Result setLna(bool bEnable);
-
-    /**
      * Link Frontend to the cicam with given id.
      *
      * @return lts id
@@ -120,7 +115,13 @@
      */
     Result close();
 
+    /**
+     * Get Frontend hardware info.
+     */
+    Result getHardwareInfo(string& info);
+
     int32_t getId();
+
     shared_ptr<ITunerFrontend> getAidlFrontend();
 private:
     /**
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index 861d78d..f917f01 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -185,4 +185,13 @@
     return nullptr;
 }
 
+Result TunerClient::setLna(bool bEnable) {
+    if (mTunerService != nullptr) {
+        Status s = mTunerService->setLna(bEnable);
+        return ClientHelper::getServiceSpecificErrorCode(s);
+    }
+
+    return Result::INVALID_STATE;
+}
+
 }  // namespace android
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 3e59e26..37b8ee1 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -127,6 +127,11 @@
      */
     sp<FilterClient> openSharedFilter(const string& filterToken, sp<FilterClientCallback> cb);
 
+    /**
+     * Enable or Disable Low Noise Amplifier (LNA).
+     */
+    Result setLna(bool bEnable);
+
 private:
     /**
      * An AIDL Tuner Service Singleton assigned at the first time the Tuner Client