Add Lnb and callback

Test: make; acloud;
Change-Id: I49a7aa5dca353a26247e8e2d86fc9379f0b917d9
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 7d68d02..3271d7b 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -35,6 +35,7 @@
     private static final int MSG_ON_FRONTEND_EVENT = 1;
     private static final int MSG_ON_FILTER_EVENT = 2;
     private static final int MSG_ON_FILTER_STATUS = 3;
+    private static final int MSG_ON_LNB_EVENT = 4;
 
     static {
         System.loadLibrary("media_tv_tuner");
@@ -45,6 +46,9 @@
     private Frontend mFrontend;
     private EventHandler mHandler;
 
+    private List<Integer> mLnbIds;
+    private Lnb mLnb;
+
     public Tuner() {
         nativeSetup();
     }
@@ -76,6 +80,8 @@
 
     private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
 
+    private native List<Integer> nativeGetLnbIds();
+    private native Lnb nativeOpenLnbById(int id);
 
     /**
      * Frontend Callback.
@@ -89,6 +95,16 @@
     }
 
     /**
+     * LNB Callback.
+     */
+    public interface LnbCallback {
+        /**
+         * Invoked when there is a LNB event.
+         */
+        void onEvent(int lnbEventType);
+    }
+
+    /**
      * Frontend Callback.
      */
     public interface FilterCallback {
@@ -129,6 +145,11 @@
                     }
                     break;
                 }
+                case MSG_ON_LNB_EVENT: {
+                    if (mLnb != null && mLnb.mCallback != null) {
+                        mLnb.mCallback.onEvent(msg.arg1);
+                    }
+                }
                 default:
                     // fall through
             }
@@ -215,4 +236,45 @@
         }
         return filter;
     }
+
+    protected class Lnb {
+        private int mId;
+        private LnbCallback mCallback;
+
+        private Lnb(int id) {
+            mId = id;
+        }
+
+        public void setCallback(@Nullable LnbCallback callback) {
+            mCallback = callback;
+            if (mCallback == null) {
+                return;
+            }
+            if (mHandler == null) {
+                mHandler = createEventHandler();
+            }
+        }
+    }
+
+    private List<Integer> getLnbIds() {
+        mLnbIds = nativeGetLnbIds();
+        return mLnbIds;
+    }
+
+    private Lnb openLnbById(int id) {
+        if (mLnbIds == null) {
+            mLnbIds = getLnbIds();
+        }
+        if (!mLnbIds.contains(id)) {
+            return null;
+        }
+        mLnb = nativeOpenLnbById(id);
+        return mLnb;
+    }
+
+    private void onLnbEvent(int eventType) {
+        if (mHandler != null) {
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_LNB_EVENT, eventType, 0));
+        }
+    }
 }
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 2640572..4c4893c 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -39,11 +39,30 @@
     jmethodID filterInitID;
     jmethodID onFrontendEventID;
     jmethodID onFilterStatusID;
+    jmethodID lnbInitID;
+    jmethodID onLnbEventID;
 };
 
 static fields_t gFields;
 
 namespace android {
+/////////////// LnbCallback ///////////////////////
+LnbCallback::LnbCallback(jweak tunerObj, LnbId id) : mObject(tunerObj), mId(id) {}
+
+Return<void> LnbCallback::onEvent(LnbEventType lnbEventType) {
+    ALOGD("LnbCallback::onEvent, type=%d", lnbEventType);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(
+            mObject,
+            gFields.onLnbEventID,
+            (jint)lnbEventType);
+    return Void();
+}
+Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) {
+    ALOGD("LnbCallback::onDiseqcMessage");
+    return Void();
+}
+
 /////////////// FilterCallback ///////////////////////
 //TODO: implement filter callback
 Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /*filterEvent*/) {
@@ -175,6 +194,52 @@
             (jint) jId);
 }
 
+jobject JTuner::getLnbIds() {
+    ALOGD("JTuner::getLnbIds()");
+    mTuner->getLnbIds([&](Result, const hidl_vec<FrontendId>& lnbIds) {
+        mLnbIds = lnbIds;
+    });
+    if (mLnbIds.size() == 0) {
+        ALOGW("Lnb 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 < mLnbIds.size(); i++) {
+       jobject idObj = env->NewObject(integerClazz, intInit, mLnbIds[i]);
+       env->CallBooleanMethod(obj, arrayListAdd, idObj);
+    }
+    return obj;
+}
+
+jobject JTuner::openLnbById(int id) {
+    sp<ILnb> lnbSp;
+    mTuner->openLnbById(id, [&](Result, const sp<ILnb>& lnb) {
+        lnbSp = lnb;
+    });
+    if (lnbSp == nullptr) {
+        ALOGE("Failed to open lnb");
+        return NULL;
+    }
+    mLnb = lnbSp;
+    sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
+    mLnb->setCallback(lnbCb);
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    return env->NewObject(
+            env->FindClass("android/media/tv/tuner/Tuner$Lnb"),
+            gFields.lnbInitID,
+            mObject,
+            id);
+}
+
 bool JTuner::openDemux() {
     if (mTuner == nullptr) {
         return false;
@@ -268,10 +333,16 @@
 
     gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V");
 
+    gFields.onLnbEventID = env->GetMethodID(clazz, "onLnbEvent", "(I)V");
+
     jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend");
     gFields.frontendInitID =
             env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
 
+    jclass lnbClazz = env->FindClass("android/media/tv/tuner/Tuner$Lnb");
+    gFields.lnbInitID =
+            env->GetMethodID(lnbClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
+
     jclass filterClazz = env->FindClass("android/media/tv/tuner/Tuner$Filter");
     gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
     gFields.filterInitID =
@@ -295,6 +366,16 @@
     return tuner->openFrontendById(id);
 }
 
+static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->getLnbIds();
+}
+
+static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz, jint id) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openLnbById(id);
+}
+
 static jobject android_media_tv_Tuner_open_filter(
         JNIEnv *env, jobject thiz, jint type, jint subType, jint bufferSize) {
     sp<JTuner> tuner = getTuner(env, thiz);
@@ -317,6 +398,10 @@
             (void *)android_media_tv_Tuner_open_frontend_by_id },
     { "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
             (void *)android_media_tv_Tuner_open_filter },
+    { "nativeGetLnbIds", "()Ljava/util/List;",
+            (void *)android_media_tv_Tuner_get_lnb_ids },
+    { "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Tuner$Lnb;",
+            (void *)android_media_tv_Tuner_open_lnb_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 ab48761..f42f032 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -37,10 +37,22 @@
 using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
 using ::android::hardware::tv::tuner::V1_0::IFrontend;
 using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using ::android::hardware::tv::tuner::V1_0::ILnb;
+using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::LnbEventType;
+using ::android::hardware::tv::tuner::V1_0::LnbId;
 
 namespace android {
 
+struct LnbCallback : public ILnbCallback {
+    LnbCallback(jweak tunerObj, LnbId id);
+    virtual Return<void> onEvent(LnbEventType lnbEventType);
+    virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
+    jweak mObject;
+    LnbId mId;
+};
+
 struct FilterCallback : public IFilterCallback {
     virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
     virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
@@ -67,7 +79,10 @@
     sp<ITuner> getTunerService();
     jobject getFrontendIds();
     jobject openFrontendById(int id);
+    jobject getLnbIds();
+    jobject openLnbById(int id);
     jobject openFilter(DemuxFilterType type, int bufferSize);
+
 protected:
     bool openDemux();
     virtual ~JTuner();
@@ -78,6 +93,8 @@
     static sp<ITuner> mTuner;
     hidl_vec<FrontendId> mFeIds;
     sp<IFrontend> mFe;
+    hidl_vec<LnbId> mLnbIds;
+    sp<ILnb> mLnb;
     sp<IDemux> mDemux;
     int mDemuxId;
 };