Add frontend constants and callback

Test: make; acloud;
Change-Id: I255aa05c9e0dddc261bb92982fec82355a6021b7
diff --git a/Android.bp b/Android.bp
index 1918ad7..b2f425cc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -303,6 +303,7 @@
         "android.hardware.thermal-V1.1-java",
         "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
+        "android.hardware.tv.tuner-V1.0-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
         "android.hardware.usb-V1.2-java-constants",
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 0228dc9..2257747 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -16,6 +16,13 @@
 
 package android.media.tv.tuner;
 
+import android.annotation.IntDef;
+import android.hardware.tv.tuner.V1_0.Constants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
 /**
  * Tuner is used to interact with tuner devices.
  *
@@ -25,11 +32,41 @@
     private static final String TAG = "MediaTvTuner";
     private static final boolean DEBUG = false;
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FRONTEND_TYPE_UNDEFINED, FRONTEND_TYPE_ANALOG, FRONTEND_TYPE_ATSC, FRONTEND_TYPE_ATSC3,
+            FRONTEND_TYPE_DVBC, FRONTEND_TYPE_DVBS, FRONTEND_TYPE_DVBT, FRONTEND_TYPE_ISDBS,
+            FRONTEND_TYPE_ISDBS3, FRONTEND_TYPE_ISDBT})
+    public @interface FrontendType {}
+
+    public static final int FRONTEND_TYPE_UNDEFINED = Constants.FrontendType.UNDEFINED;
+    public static final int FRONTEND_TYPE_ANALOG = Constants.FrontendType.ANALOG;
+    public static final int FRONTEND_TYPE_ATSC = Constants.FrontendType.ATSC;
+    public static final int FRONTEND_TYPE_ATSC3 = Constants.FrontendType.ATSC3;
+    public static final int FRONTEND_TYPE_DVBC = Constants.FrontendType.DVBC;
+    public static final int FRONTEND_TYPE_DVBS = Constants.FrontendType.DVBS;
+    public static final int FRONTEND_TYPE_DVBT = Constants.FrontendType.DVBT;
+    public static final int FRONTEND_TYPE_ISDBS = Constants.FrontendType.ISDBS;
+    public static final int FRONTEND_TYPE_ISDBS3 = Constants.FrontendType.ISDBS3;
+    public static final int FRONTEND_TYPE_ISDBT = Constants.FrontendType.ISDBT;
+
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FRONTEND_EVENT_TYPE_LOCKED, FRONTEND_EVENT_TYPE_NO_SIGNAL,
+            FRONTEND_EVENT_TYPE_LOST_LOCK})
+    public @interface FrontendEventType {}
+
+    public static final int FRONTEND_EVENT_TYPE_LOCKED = Constants.FrontendEventType.LOCKED;
+    public static final int FRONTEND_EVENT_TYPE_NO_SIGNAL = Constants.FrontendEventType.NO_SIGNAL;
+    public static final int FRONTEND_EVENT_TYPE_LOST_LOCK = Constants.FrontendEventType.LOST_LOCK;
+
     static {
         System.loadLibrary("media_tv_tuner");
         nativeInit();
     }
 
+    private FrontendCallback mFrontendCallback;
+    private List<Integer> mFrontendIds;
+
     public Tuner() {
         nativeSetup();
     }
@@ -48,4 +85,48 @@
      * Native setup.
      */
     private native void nativeSetup();
+
+    /**
+     * Native method to get all frontend IDs.
+     */
+    private native List<Integer> nativeGetFrontendIds();
+
+    /**
+     * Native method to open frontend of the given ID.
+     */
+    private native Frontend nativeOpenFrontendById(int id);
+
+
+    /**
+     * Frontend Callback.
+     */
+    public interface FrontendCallback {
+
+        /**
+         * Invoked when there is a frontend event.
+         */
+        void onEvent(int frontendEventType);
+    }
+
+    protected static class Frontend {
+        int mId;
+        private Frontend(int id) {
+            mId = id;
+        }
+    }
+
+    private List<Integer> getFrontendIds() {
+        mFrontendIds = nativeGetFrontendIds();
+        return mFrontendIds;
+    }
+
+    private Frontend openFrontendById(int id) {
+        if (mFrontendIds == null) {
+            getFrontendIds();
+        }
+        if (!mFrontendIds.contains(id)) {
+            return null;
+        }
+        return nativeOpenFrontendById(id);
+    }
 }
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index a596d89..3742f97 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -132,6 +132,7 @@
     shared_libs: [
         "android.hardware.tv.tuner@1.0",
         "libandroid_runtime",
+        "libhidlbase",
         "liblog",
         "libutils",
     ],
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index d499eee..ba133fc 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -25,10 +25,13 @@
 
 #pragma GCC diagnostic ignored "-Wunused-function"
 
+using ::android::hardware::hidl_vec;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::Result;
 
 struct fields_t {
     jfieldID context;
+    jmethodID frontendInitID;
 };
 
 static fields_t gFields;
@@ -69,6 +72,50 @@
     return mTuner;
 }
 
+jobject JTuner::getFrontendIds() {
+    ALOGD("JTuner::getFrontendIds()");
+    hidl_vec<FrontendId> feIds;
+    mTuner->getFrontendIds([&](Result, const hidl_vec<FrontendId>& frontendIds) {
+        feIds = frontendIds;
+    });
+    if (feIds.size() == 0) {
+        ALOGW("Frontend isn't available");
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass arrayListClazz = env->FindClass("java/util/ArrayList");
+    jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
+    jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
+
+    jclass integerClazz = env->FindClass("java/lang/Integer");
+    jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
+
+    for (int i=0; i < feIds.size(); i++) {
+       jobject idObj = env->NewObject(integerClazz, intInit, feIds[i]);
+       env->CallBooleanMethod(obj, arrayListAdd, idObj);
+    }
+    return obj;
+}
+
+jobject JTuner::openFrontendById(int id) {
+    mTuner->openFrontendById(id, [&](Result, const sp<IFrontend>& frontend) {
+        mFe = frontend;
+    });
+    if (mFe == nullptr) {
+        ALOGE("Failed to open frontend");
+        return NULL;
+    }
+
+    jint jId = (jint) id;
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    // TODO: add more fields to frontend
+    return env->NewObject(
+            env->FindClass("android/media/tv/tuner/Tuner$Frontend"),
+            gFields.frontendInitID,
+            (jint) jId);
+}
+
 }  // namespace android
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -99,6 +146,9 @@
 
     gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
     CHECK(gFields.context != NULL);
+
+    jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend");
+    gFields.frontendInitID = env->GetMethodID(frontendClazz, "<init>", "(I)V");
 }
 
 static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) {
@@ -106,9 +156,23 @@
     setTuner(env,thiz, tuner);
 }
 
+static jobject android_media_tv_Tuner_get_frontend_ids(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->getFrontendIds();
+}
+
+static jobject android_media_tv_Tuner_open_frontend_by_id(JNIEnv *env, jobject thiz, jint id) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openFrontendById(id);
+}
+
 static const JNINativeMethod gMethods[] = {
     { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
     { "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
+    { "nativeGetFrontendIds", "()Ljava/util/List;",
+            (void *)android_media_tv_Tuner_get_frontend_ids },
+    { "nativeOpenFrontendById", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
+            (void *)android_media_tv_Tuner_open_frontend_by_id },
 };
 
 static int register_android_media_tv_Tuner(JNIEnv *env) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index e7d5924..1425542 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -22,6 +22,8 @@
 
 #include "jni.h"
 
+using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::IFrontend;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
 
 namespace android {
@@ -29,6 +31,8 @@
 struct JTuner : public RefBase {
     JTuner(JNIEnv *env, jobject thiz);
     sp<ITuner> getTunerService();
+    jobject getFrontendIds();
+    jobject openFrontendById(int id);
 protected:
     virtual ~JTuner();
 
@@ -36,6 +40,7 @@
     jclass mClass;
     jweak mObject;
     static sp<ITuner> mTuner;
+    sp<IFrontend> mFe;
 };
 
 }  // namespace android