Add an initial TunerClient/FrontendClient interface to interact between Tuner HIDL and Tuner JNI

Test: make libmedia_tv_tuner
Bug: 174095851
Change-Id: I8f1b0c79860eb4bf8d4d16595e8b798ad691288a
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index d094c2c..c89f181 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -546,7 +546,6 @@
      */
     private native Frontend nativeOpenFrontendByHandle(int handle);
     @Result
-    private native int nativeCloseFrontendByHandle(int handle);
     private native int nativeTune(int type, FrontendSettings settings);
     private native int nativeStopTune();
     private native int nativeScan(int settingsType, FrontendSettings settings, int scanType);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index c7fb50f..979f9ec 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -139,12 +139,15 @@
     name: "libmedia_tv_tuner",
     srcs: [
         "android_media_tv_Tuner.cpp",
+        "tuner/FrontendClient.cpp",
+        "tuner/TunerClient.cpp",
     ],
 
     shared_libs: [
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.tv.tuner@1.0",
         "android.hardware.tv.tuner@1.1",
+        "libbinder_ndk",
         "libandroid_runtime",
         "libcutils",
         "libfmq",
@@ -153,6 +156,7 @@
         "libmedia",
         "libnativehelper",
         "libutils",
+        "tv_tuner_aidl_interface-ndk_platform",
     ],
     defaults: [
         "libcodec2-impl-defaults",
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 72dc32e..440d5bc 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1172,7 +1172,7 @@
 
 sp<ITuner> JTuner::mTuner;
 sp<::android::hardware::tv::tuner::V1_1::ITuner> JTuner::mTuner_1_1;
-int JTuner::mTunerVersion = 0;
+sp<TunerClient> JTuner::mTunerClient;
 
 JTuner::JTuner(JNIEnv *env, jobject thiz)
     : mClass(NULL) {
@@ -1181,9 +1181,13 @@
 
     mClass = (jclass)env->NewGlobalRef(clazz);
     mObject = env->NewWeakGlobalRef(thiz);
+    // TODO: remove after migrate to client lib
     if (mTuner == NULL) {
         mTuner = getTunerService();
     }
+    if (mTunerClient == NULL) {
+        mTunerClient = new TunerClient();
+    }
 }
 
 JTuner::~JTuner() {
@@ -1198,13 +1202,13 @@
     env->DeleteWeakGlobalRef(mObject);
     env->DeleteGlobalRef(mClass);
     mTuner = NULL;
+    mTunerClient = NULL;
     mClass = NULL;
     mObject = NULL;
 }
 
 sp<ITuner> JTuner::getTunerService() {
     if (mTuner == nullptr) {
-        mTunerVersion = 0;
         mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::getService();
 
         if (mTuner_1_1 == nullptr) {
@@ -1212,12 +1216,9 @@
             mTuner = ITuner::getService();
             if (mTuner == nullptr) {
                 ALOGW("Failed to get tuner 1.0 service.");
-            } else {
-                mTunerVersion = 1 << 16;
             }
         } else {
             mTuner = static_cast<sp<ITuner>>(mTuner_1_1);
-            mTunerVersion = ((1 << 16) | 1);
          }
      }
      return mTuner;
@@ -1225,15 +1226,13 @@
 
 jint JTuner::getTunerVersion() {
     ALOGD("JTuner::getTunerVersion()");
-    return (jint) mTunerVersion;
+    return (jint) mTunerClient->getHalTunerVersion();
 }
 
 jobject JTuner::getFrontendIds() {
     ALOGD("JTuner::getFrontendIds()");
-    mTuner->getFrontendIds([&](Result, const hidl_vec<FrontendId>& frontendIds) {
-        mFeIds = frontendIds;
-    });
-    if (mFeIds.size() == 0) {
+    vector<FrontendId> ids = mTunerClient->getFrontendIds();
+    if (ids.size() == 0) {
         ALOGW("Frontend isn't available");
         return NULL;
     }
@@ -1246,8 +1245,8 @@
     jclass integerClazz = env->FindClass("java/lang/Integer");
     jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
 
-    for (int i=0; i < mFeIds.size(); i++) {
-       jobject idObj = env->NewObject(integerClazz, intInit, mFeIds[i]);
+    for (int i=0; i < ids.size(); i++) {
+       jobject idObj = env->NewObject(integerClazz, intInit, ids[i]);
        env->CallBooleanMethod(obj, arrayListAdd, idObj);
     }
     return obj;
@@ -1284,14 +1283,6 @@
             (jint) jId);
 }
 
-jint JTuner::closeFrontendById(int id) {
-    if (mFe != NULL && mFeId == id) {
-        Result r = mFe->close();
-        return (jint) r;
-    }
-    return (jint) Result::SUCCESS;
-}
-
 jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
@@ -1402,37 +1393,26 @@
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DtmbFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIII)V");
 
-    if (mTuner_1_1 == NULL) {
-        ALOGD("1.1 Tuner is not found. Dtmb Frontend Caps are not supported.");
+    shared_ptr<FrontendDtmbCapabilities> dtmbCaps = mTunerClient->getFrontendDtmbCapabilities(id);
+    if (dtmbCaps == NULL) {
         return NULL;
     }
 
-    Result result;
-    FrontendDtmbCapabilities dtmbCaps;
-    mTuner_1_1->getFrontendDtmbCapabilities(id,
-            [&](Result r, const FrontendDtmbCapabilities& caps) {
-        dtmbCaps = caps;
-        result = r;
-    });
-    jint modulationCap = dtmbCaps.modulationCap;
-    jint transmissionModeCap = dtmbCaps.transmissionModeCap;
-    jint guardIntervalCap = dtmbCaps.guardIntervalCap;
-    jint interleaveModeCap = dtmbCaps.interleaveModeCap;
-    jint codeRateCap = dtmbCaps.codeRateCap;
-    jint bandwidthCap = dtmbCaps.bandwidthCap;
+    jint modulationCap = dtmbCaps->modulationCap;
+    jint transmissionModeCap = dtmbCaps->transmissionModeCap;
+    jint guardIntervalCap = dtmbCaps->guardIntervalCap;
+    jint interleaveModeCap = dtmbCaps->interleaveModeCap;
+    jint codeRateCap = dtmbCaps->codeRateCap;
+    jint bandwidthCap = dtmbCaps->bandwidthCap;
 
     return env->NewObject(clazz, capsInit, modulationCap, transmissionModeCap, guardIntervalCap,
             interleaveModeCap, codeRateCap, bandwidthCap);
 }
 
 jobject JTuner::getFrontendInfo(int id) {
-    FrontendInfo feInfo;
-    Result res;
-    mTuner->getFrontendInfo(id, [&](Result r, const FrontendInfo& info) {
-        feInfo = info;
-        res = r;
-    });
-    if (res != Result::SUCCESS) {
+    shared_ptr<FrontendInfo> feInfo;
+    feInfo = mTunerClient->getFrontendInfo(id);
+    if (feInfo == NULL) {
         return NULL;
     }
 
@@ -1441,30 +1421,27 @@
     jmethodID infoInit = env->GetMethodID(clazz, "<init>",
             "(IIIIIIII[ILandroid/media/tv/tuner/frontend/FrontendCapabilities;)V");
 
-    jint type = (jint) feInfo.type;
-    jint minFrequency = feInfo.minFrequency;
-    jint maxFrequency = feInfo.maxFrequency;
-    jint minSymbolRate = feInfo.minSymbolRate;
-    jint maxSymbolRate = feInfo.maxSymbolRate;
-    jint acquireRange = feInfo.acquireRange;
-    jint exclusiveGroupId = feInfo.exclusiveGroupId;
-    jintArray statusCaps = env->NewIntArray(feInfo.statusCaps.size());
+    jint type = (jint) feInfo->type;
+    jint minFrequency = feInfo->minFrequency;
+    jint maxFrequency = feInfo->maxFrequency;
+    jint minSymbolRate = feInfo->minSymbolRate;
+    jint maxSymbolRate = feInfo->maxSymbolRate;
+    jint acquireRange = feInfo->acquireRange;
+    jint exclusiveGroupId = feInfo->exclusiveGroupId;
+    jintArray statusCaps = env->NewIntArray(feInfo->statusCaps.size());
     env->SetIntArrayRegion(
-            statusCaps, 0, feInfo.statusCaps.size(),
-            reinterpret_cast<jint*>(&feInfo.statusCaps[0]));
-    FrontendInfo::FrontendCapabilities caps = feInfo.frontendCaps;
+            statusCaps, 0, feInfo->statusCaps.size(),
+            reinterpret_cast<jint*>(&feInfo->statusCaps[0]));
+    FrontendInfo::FrontendCapabilities caps = feInfo->frontendCaps;
 
     jobject jcaps = NULL;
 
-    if (feInfo.type == static_cast<FrontendType>(
+    if (feInfo->type == static_cast<FrontendType>(
             ::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) {
-        if (mTuner_1_1 == NULL) {
-            return NULL;
-        }
         jcaps = getDtmbFrontendCaps(env, id);
     }
 
-    switch(feInfo.type) {
+    switch(feInfo->type) {
         case FrontendType::ANALOG:
             if (FrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps
                     == caps.getDiscriminator()) {
@@ -3426,13 +3403,6 @@
     return tuner->openFrontendById(id);
 }
 
-static jint android_media_tv_Tuner_close_frontend_by_handle(
-        JNIEnv *env, jobject thiz, jint handle) {
-    sp<JTuner> tuner = getTuner(env, thiz);
-    uint32_t id = getResourceIdFromHandle(handle);
-    return tuner->closeFrontendById(id);
-}
-
 static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
     sp<JTuner> tuner = getTuner(env, thiz);
     FrontendSettings setting = getFrontendSettings(env, type, settings);
@@ -4746,8 +4716,6 @@
             (void *)android_media_tv_Tuner_get_frontend_ids },
     { "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
             (void *)android_media_tv_Tuner_open_frontend_by_handle },
-    { "nativeCloseFrontendByHandle", "(I)I",
-            (void *)android_media_tv_Tuner_close_frontend_by_handle },
     { "nativeTune", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;)I",
             (void *)android_media_tv_Tuner_tune },
     { "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune },
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index e79b5c2..72e30bd 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -34,6 +34,7 @@
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 
+#include "tuner/TunerClient.h"
 #include "jni.h"
 
 using ::android::hardware::EventFlag;
@@ -259,10 +260,7 @@
     jweak mObject;
     static sp<ITuner> mTuner;
     static sp<::android::hardware::tv::tuner::V1_1::ITuner> mTuner_1_1;
-    // An integer that carries the Tuner version. The high 16 bits are the major version number
-    // while the low 16 bits are the minor version. Default value is unknown version 0.
-    static int mTunerVersion;
-    hidl_vec<FrontendId> mFeIds;
+    static sp<TunerClient> mTunerClient;
     sp<IFrontend> mFe;
     sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFe_1_1;
     int mFeId;
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
new file mode 100644
index 0000000..322f01c
--- /dev/null
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FrontendClient"
+
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include "FrontendClient.h"
+
+namespace android {
+
+FrontendClient::FrontendClient(shared_ptr<ITunerFrontend> tunerFrontend) {
+    mTunerFrontend = tunerFrontend;
+}
+
+FrontendClient::~FrontendClient() {
+    mTunerFrontend = NULL;
+    mFrontend = NULL;
+    mFrontend_1_1 = NULL;
+}
+
+void FrontendClient::setHidlFrontend(sp<IFrontend> frontend) {
+    mFrontend = frontend;
+    mFrontend_1_1 = ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFrontend);
+}
+}
diff --git a/media/jni/tuner/FrontendClient.h b/media/jni/tuner/FrontendClient.h
new file mode 100644
index 0000000..56b5a97
--- /dev/null
+++ b/media/jni/tuner/FrontendClient.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_MEDIA_TV_FRONTEND_CLIENT_H_
+#define _ANDROID_MEDIA_TV_FRONTEND_CLIENT_H_
+
+#include <aidl/android/media/tv/tuner/ITunerFrontend.h>
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
+#include <android/hardware/tv/tuner/1.1/IFrontendCallback.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
+
+//#include "FrontendClientCallback"
+
+using ::aidl::android::media::tv::tuner::ITunerFrontend;
+
+using ::android::hardware::tv::tuner::V1_0::FrontendInfo;
+using ::android::hardware::tv::tuner::V1_0::IFrontend;
+
+using namespace std;
+
+namespace android {
+
+struct FrontendClient : public RefBase {
+    FrontendClient(shared_ptr<ITunerFrontend> tunerFrontend);
+    ~FrontendClient();
+
+    void setHidlFrontend(sp<IFrontend> frontend);
+
+private:
+    /**
+     * An AIDL Tuner Frontend Singleton assigned at the first time when the Tuner Client
+     * opens a frontend cient. Default null when the service does not exist.
+     */
+    shared_ptr<ITunerFrontend> mTunerFrontend;
+
+    /**
+     * A Frontend 1.0 HAL interface as a fall back interface when the Tuner Service does not exist.
+     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
+     * Default null.
+     */
+    sp<IFrontend> mFrontend;
+
+    /**
+     * A Frontend 1.1 HAL interface as a fall back interface when the Tuner Service does not exist.
+     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
+     * Default null.
+     */
+    sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFrontend_1_1;
+};
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_TV_FRONTEND_CLIENT_H_
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
new file mode 100644
index 0000000..4665f2b
--- /dev/null
+++ b/media/jni/tuner/TunerClient.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "TunerClient"
+
+#include <android/binder_manager.h>
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include "TunerClient.h"
+
+using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::FrontendType;
+
+namespace android {
+
+sp<ITuner> TunerClient::mTuner;
+sp<::android::hardware::tv::tuner::V1_1::ITuner> TunerClient::mTuner_1_1;
+shared_ptr<ITunerService> TunerClient::mTunerService;
+int TunerClient::mTunerVersion;
+
+/////////////// TunerClient ///////////////////////
+
+TunerClient::TunerClient() {
+    // Get HIDL Tuner in migration stage.
+    getHidlTuner();
+    // Connect with Tuner Service.
+    ::ndk::SpAIBinder binder(AServiceManager_getService("media.tuner"));
+    mTunerService = ITunerService::fromBinder(binder);
+    if (mTunerService == NULL) {
+        ALOGE("Failed to get tuner service");
+    }
+}
+
+TunerClient::~TunerClient() {
+    mTuner = NULL;
+    mTuner_1_1 = NULL;
+    mTunerVersion = 0;
+    mTunerService = NULL;
+}
+
+vector<FrontendId> TunerClient::getFrontendIds() {
+    vector<FrontendId> ids;
+    // TODO: pending aidl interface
+    /*if (mTunerService != NULL) {
+        return mTunerService->getFrontendIds();
+    }*/
+
+    if (mTuner != NULL) {
+        Result res;
+        mTuner->getFrontendIds([&](Result r, const hardware::hidl_vec<FrontendId>& frontendIds) {
+            res = r;
+            ids = frontendIds;
+        });
+        if (res != Result::SUCCESS || ids.size() == 0) {
+            ALOGW("Frontend ids not available");
+            ids.clear();
+            return ids;
+        }
+        return ids;
+    }
+
+    return ids;
+}
+
+
+sp<FrontendClient> TunerClient::openFrontend(int frontendHandle) {
+    if (mTunerService != NULL) {
+        // TODO: handle error code
+        shared_ptr<ITunerFrontend> tunerFrontend;
+        mTunerService->openFrontend(frontendHandle, &tunerFrontend);
+        return new FrontendClient(tunerFrontend);
+    }
+
+    if (mTuner != NULL) {
+        sp<IFrontend> hidlFrontend = openHidlFrontendByHandle(frontendHandle);
+        if (hidlFrontend != NULL) {
+            sp<FrontendClient> frontendClient = new FrontendClient(NULL);
+            frontendClient->setHidlFrontend(hidlFrontend);
+            return frontendClient;
+        }
+    }
+
+    return NULL;
+}
+
+shared_ptr<FrontendInfo> TunerClient::getFrontendInfo(int id) {
+    if (mTunerService != NULL) {
+        TunerServiceFrontendInfo aidlFrontendInfo;
+        // TODO: handle error code
+        mTunerService->getFrontendInfo(id, &aidlFrontendInfo);
+        return make_shared<FrontendInfo>(FrontendInfoAidlToHidl(aidlFrontendInfo));
+    }
+
+    if (mTuner != NULL) {
+        FrontendInfo hidlInfo;
+        Result res = getHidlFrontendInfo(id, hidlInfo);
+        if (res != Result::SUCCESS) {
+            return NULL;
+        }
+        return make_shared<FrontendInfo>(hidlInfo);
+    }
+
+    return NULL;
+}
+
+shared_ptr<FrontendDtmbCapabilities> TunerClient::getFrontendDtmbCapabilities(int id) {
+    // pending aidl interface
+
+    if (mTuner_1_1 != NULL) {
+        Result result;
+        FrontendDtmbCapabilities dtmbCaps;
+        mTuner_1_1->getFrontendDtmbCapabilities(id,
+                [&](Result r, const FrontendDtmbCapabilities& caps) {
+            dtmbCaps = caps;
+            result = r;
+        });
+        if (result == Result::SUCCESS) {
+            return make_shared<FrontendDtmbCapabilities>(dtmbCaps);
+        }
+    }
+
+    return NULL;
+}
+
+/////////////// TunerClient Helper Methods ///////////////////////
+
+sp<ITuner> TunerClient::getHidlTuner() {
+    if (mTuner == NULL) {
+        mTunerVersion = 0;
+        mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::getService();
+
+        if (mTuner_1_1 == NULL) {
+            ALOGW("Failed to get tuner 1.1 service.");
+            mTuner = ITuner::getService();
+            if (mTuner == NULL) {
+                ALOGW("Failed to get tuner 1.0 service.");
+            } else {
+                mTunerVersion = 1 << 16;
+            }
+        } else {
+            mTuner = static_cast<sp<ITuner>>(mTuner_1_1);
+            mTunerVersion = ((1 << 16) | 1);
+         }
+     }
+     return mTuner;
+}
+
+sp<IFrontend> TunerClient::openHidlFrontendByHandle(int frontendHandle) {
+    sp<IFrontend> fe;
+    Result res;
+    uint32_t id = getResourceIdFromHandle(frontendHandle);
+    mTuner->openFrontendById(id, [&](Result r, const sp<IFrontend>& frontend) {
+        fe = frontend;
+        res = r;
+    });
+    if (res != Result::SUCCESS || fe == nullptr) {
+        ALOGE("Failed to open frontend");
+        return NULL;
+    }
+    return fe;
+}
+
+Result TunerClient::getHidlFrontendInfo(int id, FrontendInfo& feInfo) {
+    Result res;
+    mTuner->getFrontendInfo(id, [&](Result r, const FrontendInfo& info) {
+        feInfo = info;
+        res = r;
+    });
+    return res;
+}
+
+FrontendInfo TunerClient::FrontendInfoAidlToHidl(TunerServiceFrontendInfo aidlFrontendInfo) {
+    FrontendInfo hidlFrontendInfo {
+        .type = static_cast<FrontendType>(aidlFrontendInfo.type),
+        .minFrequency = static_cast<uint32_t>(aidlFrontendInfo.minFrequency),
+        .maxFrequency = static_cast<uint32_t>(aidlFrontendInfo.maxFrequency),
+        .minSymbolRate = static_cast<uint32_t>(aidlFrontendInfo.minSymbolRate),
+        .maxSymbolRate = static_cast<uint32_t>(aidlFrontendInfo.maxSymbolRate),
+        .acquireRange = static_cast<uint32_t>(aidlFrontendInfo.acquireRange),
+        .exclusiveGroupId = static_cast<uint32_t>(aidlFrontendInfo.exclusiveGroupId),
+    };
+    // TODO: handle Frontend caps
+
+    return hidlFrontendInfo;
+}
+}  // namespace android
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
new file mode 100644
index 0000000..f2e78c9
--- /dev/null
+++ b/media/jni/tuner/TunerClient.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_MEDIA_TV_TUNER_CLIENT_H_
+#define _ANDROID_MEDIA_TV_TUNER_CLIENT_H_
+
+#include <aidl/android/media/tv/tuner/ITunerService.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
+
+#include "FrontendClient.h"
+
+using ::aidl::android::media::tv::tuner::ITunerService;
+using ::aidl::android::media::tv::tuner::TunerServiceFrontendInfo;
+
+using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
+using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::Result;
+using ::android::hardware::tv::tuner::V1_1::FrontendDtmbCapabilities;
+
+using namespace std;
+
+namespace android {
+
+struct TunerClient : public RefBase {
+
+public:
+    TunerClient();
+    ~TunerClient();
+
+    /**
+     * Retrieve all the frontend ids.
+     *
+     * @return a list of the available frontend ids
+     */
+    vector<FrontendId> getFrontendIds();
+
+    /**
+     * Open a new interface of FrontendClient given a frontendHandle.
+     *
+     * @param frontendHandle the handle of the frontend granted by TRM.
+     * @return a newly created FrontendClient interface.
+     */
+    sp<FrontendClient> openFrontend(int frontendHandle);
+
+    /**
+     * Retrieve the granted frontend's information.
+     *
+     * @param id the id of the frontend granted by TRM.
+     * @return the information for the frontend.
+     */
+    shared_ptr<FrontendInfo> getFrontendInfo(int id);
+
+    /**
+     * Retrieve the DTMB frontend's capabilities.
+     *
+     * @param id the id of the DTMB frontend.
+     * @return the capabilities of the frontend.
+     */
+    shared_ptr<FrontendDtmbCapabilities> getFrontendDtmbCapabilities(int id);
+
+    /**
+     * Get the current Tuner HAL version. The high 16 bits are the major version number
+     * while the low 16 bits are the minor version. Default value is unknown version 0.
+     */
+    int getHalTunerVersion() { return mTunerVersion; }
+
+    static int getResourceIdFromHandle(int handle) {
+        return (handle & 0x00ff0000) >> 16;
+    }
+
+private:
+    /**
+     * An AIDL Tuner Service Singleton assigned at the first time the Tuner Client
+     * connects with the Tuner Service. Default null when the service does not exist.
+     */
+    static shared_ptr<ITunerService> mTunerService;
+
+    /**
+     * A Tuner 1.0 HAL interface that is ready before connecting to the TunerService
+     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
+     * Default null.
+     */
+    static sp<ITuner> mTuner;
+
+    /**
+     * A Tuner 1.1 HAL interface that is ready before connecting to the TunerService
+     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
+     * Default null.
+     */
+    static sp<::android::hardware::tv::tuner::V1_1::ITuner> mTuner_1_1;
+
+    // An integer that carries the Tuner version. The high 16 bits are the major version number
+    // while the low 16 bits are the minor version. Default value is unknown version 0.
+    static int mTunerVersion;
+
+    sp<ITuner> getHidlTuner();
+    sp<IFrontend> openHidlFrontendByHandle(int frontendHandle);
+    Result getHidlFrontendInfo(int id, FrontendInfo& info);
+    FrontendInfo FrontendInfoAidlToHidl(TunerServiceFrontendInfo aidlFrontendInfo);
+};
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_TV_TUNER_CLIENT_H_