Create Broadcast radio HAL 1.1; implement DigitalStatus enum.

Test: VTS
Change-Id: I338c467c4e373cae547f331ba876afa040238376
diff --git a/broadcastradio/1.1/vts/Android.mk b/broadcastradio/1.1/vts/Android.mk
new file mode 100644
index 0000000..0c4c55d
--- /dev/null
+++ b/broadcastradio/1.1/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2017 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..e10ddab
--- /dev/null
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+    name: "VtsHalBroadcastradioV1_1TargetTest",
+    gtest: true,
+    srcs: ["VtsHalBroadcastradioV1_1TargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.broadcastradio@1.0",
+        "android.hardware.broadcastradio@1.1",
+    ],
+    static_libs: ["libgtest"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
new file mode 100644
index 0000000..873a10b
--- /dev/null
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2017 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 "BroadcastRadioHidlHalTest"
+#include <gtest/gtest.h>
+#include <android-base/logging.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/threads.h>
+
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.1/ITuner.h>
+#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.1/types.h>
+
+
+namespace V1_0 = ::android::hardware::broadcastradio::V1_0;
+
+using ::android::sp;
+using ::android::Mutex;
+using ::android::Condition;
+using ::android::hardware::Return;
+using ::android::hardware::Status;
+using ::android::hardware::Void;
+using ::android::hardware::broadcastradio::V1_0::BandConfig;
+using ::android::hardware::broadcastradio::V1_0::Class;
+using ::android::hardware::broadcastradio::V1_0::Direction;
+using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
+using ::android::hardware::broadcastradio::V1_0::MetaData;
+using ::android::hardware::broadcastradio::V1_0::Properties;
+using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory;
+using ::android::hardware::broadcastradio::V1_1::ITuner;
+using ::android::hardware::broadcastradio::V1_1::ITunerCallback;
+using ::android::hardware::broadcastradio::V1_1::ProgramInfo;
+using ::android::hardware::broadcastradio::V1_1::Result;
+
+
+// The main test class for Broadcast Radio HIDL HAL.
+
+class BroadcastRadioHidlTest : public ::testing::Test {
+ protected:
+    virtual void SetUp() override {
+        bool getStub = false;
+        char getsubProperty[PROPERTY_VALUE_MAX];
+        if (property_get("vts.hidl.get_stub", getsubProperty, "") > 0) {
+            if (!strcmp(getsubProperty, "true") ||
+                    !strcmp(getsubProperty, "True") ||
+                    !strcmp(getsubProperty, "1")) {
+                getStub = true;
+            }
+        }
+        auto factory = IBroadcastRadioFactory::getService(getStub);
+        if (factory != 0) {
+            factory->connectModule(Class::AM_FM,
+                             [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
+                if (retval == Result::OK) {
+                  mRadio = IBroadcastRadio::castFrom(result);
+                }
+            });
+        }
+        mTunerCallback = new MyCallback(this);
+        ASSERT_NE(nullptr, mRadio.get());
+        ASSERT_EQ(!getStub, mRadio->isRemote());
+        ASSERT_NE(nullptr, mTunerCallback.get());
+    }
+
+    virtual void TearDown() override {
+        mTuner.clear();
+        mRadio.clear();
+    }
+
+    class MyCallback : public ITunerCallback {
+     public:
+
+        // ITunerCallback methods (see doc in ITunerCallback.hal)
+        virtual Return<void> hardwareFailure() {
+            ALOGI("%s", __FUNCTION__);
+            mParentTest->onHwFailureCallback();
+            return Void();
+        }
+
+        virtual Return<void> configChange(Result result, const BandConfig& config __unused) {
+            ALOGI("%s result %d", __FUNCTION__, result);
+            mParentTest->onResultCallback(result);
+            return Void();
+        }
+
+        virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) {
+            return Void();
+        }
+
+        virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) {
+            ALOGI("%s result %d", __FUNCTION__, result);
+            mParentTest->onResultCallback(result);
+            return Void();
+        }
+
+        virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) {
+            return Void();
+        }
+
+        virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) {
+            return Void();
+        }
+
+        virtual Return<void> antennaStateChange(bool connected) {
+            ALOGI("%s connected %d", __FUNCTION__, connected);
+            return Void();
+        }
+
+        virtual Return<void> trafficAnnouncement(bool active) {
+            ALOGI("%s active %d", __FUNCTION__, active);
+            return Void();
+        }
+
+        virtual Return<void> emergencyAnnouncement(bool active) {
+            ALOGI("%s active %d", __FUNCTION__, active);
+            return Void();
+        }
+
+        virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
+                           const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        }
+
+                MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
+
+     private:
+        // BroadcastRadioHidlTest instance to which callbacks will be notified.
+        BroadcastRadioHidlTest *mParentTest;
+    };
+
+
+    /**
+     * Method called by MyCallback when a callback with no status or boolean value is received
+     */
+    void onCallback() {
+        Mutex::Autolock _l(mLock);
+        onCallback_l();
+    }
+
+    /**
+     * Method called by MyCallback when hardwareFailure() callback is received
+     */
+    void onHwFailureCallback() {
+        Mutex::Autolock _l(mLock);
+        mHwFailure = true;
+        onCallback_l();
+    }
+
+    /**
+     * Method called by MyCallback when a callback with status is received
+     */
+    void onResultCallback(Result result) {
+        Mutex::Autolock _l(mLock);
+        mResultCallbackData = result;
+        onCallback_l();
+    }
+
+    /**
+     * Method called by MyCallback when a boolean indication is received
+     */
+    void onBoolCallback(bool result) {
+        Mutex::Autolock _l(mLock);
+        mBoolCallbackData = result;
+        onCallback_l();
+    }
+
+
+        BroadcastRadioHidlTest() :
+            mCallbackCalled(false), mBoolCallbackData(false),
+            mResultCallbackData(Result::OK), mHwFailure(false) {}
+
+    void onCallback_l() {
+        if (!mCallbackCalled) {
+            mCallbackCalled = true;
+            mCallbackCond.broadcast();
+        }
+    }
+
+
+    bool waitForCallback(nsecs_t reltime = 0) {
+        Mutex::Autolock _l(mLock);
+        nsecs_t endTime = systemTime() + reltime;
+        while (!mCallbackCalled) {
+            if (reltime == 0) {
+                mCallbackCond.wait(mLock);
+            } else {
+                nsecs_t now = systemTime();
+                if (now > endTime) {
+                    return false;
+                }
+                mCallbackCond.waitRelative(mLock, endTime - now);
+            }
+        }
+        return true;
+    }
+
+    bool getProperties();
+    bool openTuner();
+    bool checkAntenna();
+
+    static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
+    static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
+
+    sp<IBroadcastRadio> mRadio;
+    Properties mHalProperties;
+    sp<ITuner> mTuner;
+    sp<MyCallback> mTunerCallback;
+    Mutex mLock;
+    Condition mCallbackCond;
+    bool mCallbackCalled;
+    bool mBoolCallbackData;
+    Result mResultCallbackData;
+    bool mHwFailure;
+};
+
+// A class for test environment setup (kept since this file is a template).
+class BroadcastRadioHidlEnvironment : public ::testing::Environment {
+ public:
+    virtual void SetUp() {}
+    virtual void TearDown() {}
+};
+
+bool BroadcastRadioHidlTest::getProperties()
+{
+    if (mHalProperties.bands.size() == 0) {
+        Result halResult = Result::NOT_INITIALIZED;
+        Return<void> hidlReturn =
+                mRadio->getProperties([&](Result result, const Properties& properties) {
+                        halResult = result;
+                        if (result == Result::OK) {
+                            mHalProperties = properties;
+                        }
+                    });
+
+        EXPECT_TRUE(hidlReturn.isOk());
+        EXPECT_EQ(Result::OK, halResult);
+        EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
+        EXPECT_GT(mHalProperties.numTuners, 0u);
+        EXPECT_GT(mHalProperties.bands.size(), 0u);
+    }
+    return mHalProperties.bands.size() > 0;
+}
+
+bool BroadcastRadioHidlTest::openTuner()
+{
+    if (!getProperties()) {
+        return false;
+    }
+    if (mTuner.get() == nullptr) {
+        Result halResult = Result::NOT_INITIALIZED;
+        auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
+                [&](Result result, const sp<V1_0::ITuner>& tuner) {
+                    halResult = result;
+                    if (result == Result::OK) {
+                        mTuner = ITuner::castFrom(tuner);
+                    }
+                });
+        EXPECT_TRUE(hidlReturn.isOk());
+        EXPECT_EQ(Result::OK, halResult);
+        EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+    }
+    EXPECT_NE(nullptr, mTuner.get());
+    return nullptr != mTuner.get();
+}
+
+bool BroadcastRadioHidlTest::checkAntenna()
+{
+    BandConfig halConfig;
+    Result halResult = Result::NOT_INITIALIZED;
+    Return<void> hidlReturn =
+            mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+                halResult = result;
+                if (result == Result::OK) {
+                    halConfig = config;
+                }
+            });
+
+    return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
+}
+
+
+/**
+ * Test IBroadcastRadio::getProperties() method
+ *
+ * Verifies that:
+ *  - the HAL implements the method
+ *  - the method returns 0 (no error)
+ *  - the implementation class is AM_FM
+ *  - the implementation supports at least one tuner
+ *  - the implementation supports at one band
+ */
+TEST_F(BroadcastRadioHidlTest, GetProperties) {
+    EXPECT_TRUE(getProperties());
+}
+
+/**
+ * Test IBroadcastRadio::openTuner() method
+ *
+ * Verifies that:
+ *  - the HAL implements the method
+ *  - the method returns 0 (no error) and a valid ITuner interface
+ */
+TEST_F(BroadcastRadioHidlTest, OpenTuner) {
+    EXPECT_TRUE(openTuner());
+}
+
+/**
+ * Test ITuner::setConfiguration() and getConfiguration methods
+ *
+ * Verifies that:
+ *  - the HAL implements both methods
+ *  - the methods return 0 (no error)
+ *  - the configuration callback is received within kConfigCallbacktimeoutNs ns
+ *  - the configuration read back from HAl has the same class Id
+ */
+TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) {
+    ASSERT_TRUE(openTuner());
+    // test setConfiguration
+    mCallbackCalled = false;
+    Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, hidlResult);
+    EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+    EXPECT_EQ(Result::OK, mResultCallbackData);
+
+    // test getConfiguration
+    BandConfig halConfig;
+    Result halResult;
+    Return<void> hidlReturn =
+            mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+                halResult = result;
+                if (result == Result::OK) {
+                    halConfig = config;
+                }
+            });
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(Result::OK, halResult);
+    EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
+}
+
+/**
+ * Test ITuner::scan
+ *
+ * Verifies that:
+ *  - the HAL implements the method
+ *  - the method returns 0 (no error)
+ *  - the tuned callback is received within kTuneCallbacktimeoutNs ns
+ */
+TEST_F(BroadcastRadioHidlTest, Scan) {
+    ASSERT_TRUE(openTuner());
+    ASSERT_TRUE(checkAntenna());
+    // test scan UP
+    mCallbackCalled = false;
+    Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, hidlResult);
+    EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+    // test scan DOWN
+    mCallbackCalled = false;
+    hidlResult = mTuner->scan(Direction::DOWN, true);
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, hidlResult);
+    EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+}
+
+/**
+ * Test ITuner::step
+ *
+ * Verifies that:
+ *  - the HAL implements the method
+ *  - the method returns 0 (no error)
+ *  - the tuned callback is received within kTuneCallbacktimeoutNs ns
+ */
+TEST_F(BroadcastRadioHidlTest, Step) {
+    ASSERT_TRUE(openTuner());
+    ASSERT_TRUE(checkAntenna());
+    // test step UP
+    mCallbackCalled = false;
+    Return<Result> hidlResult = mTuner->step(Direction::UP, true);
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, hidlResult);
+    EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+    // test step DOWN
+    mCallbackCalled = false;
+    hidlResult = mTuner->step(Direction::DOWN, true);
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, hidlResult);
+    EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+}
+
+/**
+ * Test ITuner::tune,  getProgramInformation and cancel methods
+ *
+ * Verifies that:
+ *  - the HAL implements the methods
+ *  - the methods return 0 (no error)
+ *  - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
+ */
+TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
+    ASSERT_TRUE(openTuner());
+    ASSERT_TRUE(checkAntenna());
+
+    // test tune
+    ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
+    ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
+
+    // test scan UP
+    uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
+    uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
+    uint32_t spacing = mHalProperties.bands[0].spacings[0];
+
+    uint32_t channel =
+            lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
+    mCallbackCalled = false;
+    mResultCallbackData = Result::NOT_INITIALIZED;
+    Return<Result> hidlResult = mTuner->tune(channel, 0);
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, hidlResult);
+    EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+    // test getProgramInformation
+    ProgramInfo halInfo;
+    Result halResult = Result::NOT_INITIALIZED;
+    Return<void> hidlReturn = mTuner->getProgramInformation_1_1(
+        [&](Result result, const ProgramInfo& info) {
+            halResult = result;
+            if (result == Result::OK) {
+                halInfo = info;
+            }
+        });
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(Result::OK, halResult);
+    auto &halInfo_1_1 = halInfo.base;
+    if (mResultCallbackData == Result::OK) {
+        EXPECT_TRUE(halInfo_1_1.tuned);
+        EXPECT_LE(halInfo_1_1.channel, upperLimit);
+        EXPECT_GE(halInfo_1_1.channel, lowerLimit);
+    } else {
+        EXPECT_EQ(false, halInfo_1_1.tuned);
+    }
+
+    // test cancel
+    mTuner->tune(lowerLimit, 0);
+    hidlResult = mTuner->cancel();
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, hidlResult);
+}
+
+
+int main(int argc, char** argv) {
+  ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}