Implement broadcast radio announcements.

Bug: 68045105
Test: VTS
Change-Id: I14d394862ec34d63218c938779e217c28710e230
diff --git a/broadcastradio/2.0/Android.bp b/broadcastradio/2.0/Android.bp
index f4894ad..7409005 100644
--- a/broadcastradio/2.0/Android.bp
+++ b/broadcastradio/2.0/Android.bp
@@ -8,7 +8,9 @@
     },
     srcs: [
         "types.hal",
+        "IAnnouncementObserver.hal",
         "IBroadcastRadio.hal",
+        "ICloseHandle.hal",
         "ITunerCallback.hal",
         "ITunerSession.hal",
     ],
@@ -18,6 +20,8 @@
     types: [
         "AmFmBandRange",
         "AmFmRegionConfig",
+        "Announcement",
+        "AnnouncementType",
         "ConfigFlag",
         "Constants",
         "DabTableEntry",
diff --git a/broadcastradio/2.0/IAnnouncementObserver.hal b/broadcastradio/2.0/IAnnouncementObserver.hal
new file mode 100644
index 0000000..c91e29a
--- /dev/null
+++ b/broadcastradio/2.0/IAnnouncementObserver.hal
@@ -0,0 +1,30 @@
+/* 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.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+/**
+ * Callback interface for announcement observer.
+ *
+ * For typical configuration, the observer is a broadcast radio service.
+ */
+interface IAnnouncementObserver {
+    /**
+     * Called whenever announcement list has changed.
+     *
+     * @param announcements The complete list of currently active announcements.
+     */
+    oneway onListUpdated(vec<Announcement> announcements);
+};
diff --git a/broadcastradio/2.0/IBroadcastRadio.hal b/broadcastradio/2.0/IBroadcastRadio.hal
index 3b19e61..7578f44 100644
--- a/broadcastradio/2.0/IBroadcastRadio.hal
+++ b/broadcastradio/2.0/IBroadcastRadio.hal
@@ -15,6 +15,8 @@
 
 package android.hardware.broadcastradio@2.0;
 
+import IAnnouncementObserver;
+import ICloseHandle;
 import ITunerCallback;
 import ITunerSession;
 
@@ -66,7 +68,7 @@
      * @return session The session interface.
      */
     openSession(ITunerCallback callback)
-            generates (Result result, ITunerSession session);
+        generates (Result result, ITunerSession session);
 
     /**
      * Fetch image from radio module cache.
@@ -100,4 +102,28 @@
      *               or a zero-length vector if identifier doesn't exist.
      */
     getImage(uint32_t id) generates (vec<uint8_t> image);
+
+    /**
+     * Registers announcement observer.
+     *
+     * If there is at least one observer registered, HAL implementation must
+     * notify about announcements even if no sessions are active.
+     *
+     * If the observer dies, the HAL implementation must unregister observer
+     * automatically.
+     *
+     * @param enabled The list of announcement types to watch for.
+     * @param cb The callback interface.
+     * @return result OK in case of success.
+     *                NOT_SUPPORTED if the tuner doesn't support announcements.
+     * @return closeHandle A handle to unregister observer,
+     *                     nullptr if result was not OK.
+     */
+    registerAnnouncementObserver(
+            vec<AnnouncementType> enabled,
+            IAnnouncementObserver cb
+        ) generates (
+            Result result,
+            ICloseHandle closeHandle
+        );
 };
diff --git a/broadcastradio/2.0/ICloseHandle.hal b/broadcastradio/2.0/ICloseHandle.hal
new file mode 100644
index 0000000..34cea14
--- /dev/null
+++ b/broadcastradio/2.0/ICloseHandle.hal
@@ -0,0 +1,32 @@
+/* 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.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ */
+interface ICloseHandle {
+    /**
+     * Closes the handle.
+     *
+     * The call must not fail and must only be issued once.
+     *
+     * After the close call is executed, no other calls to this interface
+     * are allowed.
+     */
+    close();
+};
diff --git a/broadcastradio/2.0/ITunerSession.hal b/broadcastradio/2.0/ITunerSession.hal
index a3f93fd..a58fa62 100644
--- a/broadcastradio/2.0/ITunerSession.hal
+++ b/broadcastradio/2.0/ITunerSession.hal
@@ -154,7 +154,7 @@
      * @return results Operation completion status for parameters being set.
      */
     setParameters(vec<VendorKeyValue> parameters)
-            generates (vec<VendorKeyValue> results);
+        generates (vec<VendorKeyValue> results);
 
     /**
      * Generic method for retrieving vendor-specific parameter values.
diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp
index 5dde8a7..d16aaff 100644
--- a/broadcastradio/2.0/default/BroadcastRadio.cpp
+++ b/broadcastradio/2.0/default/BroadcastRadio.cpp
@@ -141,6 +141,15 @@
     return {};
 }
 
+Return<void> BroadcastRadio::registerAnnouncementObserver(
+    const hidl_vec<AnnouncementType>& enabled, const sp<IAnnouncementObserver>& /* cb */,
+    registerAnnouncementObserver_cb _hidl_cb) {
+    ALOGV("%s(%s)", __func__, toString(enabled).c_str());
+
+    _hidl_cb(Result::NOT_SUPPORTED, nullptr);
+    return {};
+}
+
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace broadcastradio
diff --git a/broadcastradio/2.0/default/BroadcastRadio.h b/broadcastradio/2.0/default/BroadcastRadio.h
index 733cadf..7904946 100644
--- a/broadcastradio/2.0/default/BroadcastRadio.h
+++ b/broadcastradio/2.0/default/BroadcastRadio.h
@@ -36,6 +36,9 @@
     Return<void> getDabRegionConfig(getDabRegionConfig_cb _hidl_cb);
     Return<void> openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) override;
     Return<void> getImage(uint32_t id, getImage_cb _hidl_cb);
+    Return<void> registerAnnouncementObserver(const hidl_vec<AnnouncementType>& enabled,
+                                              const sp<IAnnouncementObserver>& cb,
+                                              registerAnnouncementObserver_cb _hidl_cb);
 
     std::reference_wrapper<const VirtualRadio> mVirtualRadio;
     Properties mProperties;
diff --git a/broadcastradio/2.0/types.hal b/broadcastradio/2.0/types.hal
index 38a5709..d77e8c1 100644
--- a/broadcastradio/2.0/types.hal
+++ b/broadcastradio/2.0/types.hal
@@ -777,3 +777,55 @@
      */
     bool excludeModifications;
 };
+
+/**
+ * Type of an announcement.
+ *
+ * It maps to different announcement types per each radio technology.
+ */
+enum AnnouncementType : uint8_t {
+    /** DAB alarm, RDS emergency program type (PTY 31). */
+    EMERGENCY = 1,
+
+    /** DAB warning. */
+    WARNING,
+
+    /** DAB road traffic, RDS TA, HD Radio transportation. */
+    TRAFFIC,
+
+    /** Weather. */
+    WEATHER,
+
+    /** News. */
+    NEWS,
+
+    /** DAB event, special event. */
+    EVENT,
+
+    /** DAB sport report, RDS sports. */
+    SPORT,
+
+    /** All others. */
+    MISC,
+};
+
+/**
+ * A pointer to a station broadcasting active announcement.
+ */
+struct Announcement {
+    /**
+     * Program selector to tune to the announcement.
+     */
+    ProgramSelector selector;
+
+    /** Announcement type. */
+    AnnouncementType type;
+
+    /**
+     * Vendor-specific information.
+     *
+     * It may be used for extra features, not supported by the platform,
+     * for example: com.me.hdradio.urgency=100; com.me.hdradio.certainity=50.
+     */
+    vec<VendorKeyValue> vendorInfo;
+};
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 87ac934..aa75442 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -89,6 +89,10 @@
     utils::ProgramInfoSet mProgramList;
 };
 
+struct AnnouncementObserverMock : public IAnnouncementObserver {
+    MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
+};
+
 class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
    protected:
     virtual void SetUp() override;
@@ -660,6 +664,40 @@
     EXPECT_TRUE(stopResult.isOk());
 }
 
+/**
+ * Test announcement observer registration.
+ *
+ * Verifies that:
+ *  - registerAnnouncementObserver either succeeds or returns NOT_SUPPORTED;
+ *  - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
+ *  - closing handle does not crash.
+ */
+TEST_F(BroadcastRadioHalTest, AnnouncementObserverRegistration) {
+    sp<AnnouncementObserverMock> observer = new AnnouncementObserverMock();
+
+    Result halResult = Result::UNKNOWN_ERROR;
+    sp<ICloseHandle> closeHandle = nullptr;
+    auto cb = [&](Result result, const sp<ICloseHandle>& closeHandle_) {
+        halResult = result;
+        closeHandle = closeHandle_;
+    };
+
+    auto hidlResult =
+        mModule->registerAnnouncementObserver({AnnouncementType::EMERGENCY}, observer, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+
+    if (halResult == Result::NOT_SUPPORTED) {
+        ASSERT_EQ(nullptr, closeHandle.get());
+        printSkipped("Announcements not supported");
+        return;
+    }
+
+    ASSERT_EQ(Result::OK, halResult);
+    ASSERT_NE(nullptr, closeHandle.get());
+
+    closeHandle->close();
+}
+
 // TODO(b/70939328): test ProgramInfo's currentlyTunedId and
 // currentlyTunedChannel once the program list is implemented.