Adds default implementation for ultrasonics HAL

- Replicates logic from camera for default impl.

Bug: 148619310
Fixes: b/148608401
Test: Builds, VTS passes.

Change-Id: I5c1b4c615f98cb7405a9a233a7853daba09cc63d
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index 415841c..117ee7a 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -19,6 +19,7 @@
 #include "EvsEnumerator.h"
 #include "EvsCamera.h"
 #include "EvsDisplay.h"
+#include "EvsUltrasonicsArray.h"
 
 namespace android {
 namespace hardware {
@@ -31,12 +32,12 @@
 // NOTE:  All members values are static so that all clients operate on the same state
 //        That is to say, this is effectively a singleton despite the fact that HIDL
 //        constructs a new instance for each client.
-std::list<EvsEnumerator::CameraRecord>   EvsEnumerator::sCameraList;
-wp<EvsDisplay>                           EvsEnumerator::sActiveDisplay;
-unique_ptr<ConfigManager>                EvsEnumerator::sConfigManager;
-sp<IAutomotiveDisplayProxyService>       EvsEnumerator::sDisplayProxyService;
-std::unordered_map<uint8_t, uint64_t>    EvsEnumerator::sDisplayPortList;
-
+std::list<EvsEnumerator::CameraRecord>              EvsEnumerator::sCameraList;
+wp<EvsDisplay>                                      EvsEnumerator::sActiveDisplay;
+unique_ptr<ConfigManager>                           EvsEnumerator::sConfigManager;
+sp<IAutomotiveDisplayProxyService>                  EvsEnumerator::sDisplayProxyService;
+std::unordered_map<uint8_t, uint64_t>               EvsEnumerator::sDisplayPortList;
+std::list<EvsEnumerator::UltrasonicsArrayRecord>    EvsEnumerator::sUltrasonicsArrayRecordList;
 
 EvsEnumerator::EvsEnumerator(sp<IAutomotiveDisplayProxyService> windowService) {
     ALOGD("EvsEnumerator created");
@@ -66,6 +67,10 @@
             }
         });
     }
+
+    // Add ultrasonics array desc.
+    sUltrasonicsArrayRecordList.emplace_back(
+            EvsUltrasonicsArray::GetDummyArrayDesc("front_array"));
 }
 
 
@@ -355,25 +360,99 @@
     return pRecord;
 }
 
-// TODO(b/148608401): Add default implementation with dummy data.
+EvsEnumerator::UltrasonicsArrayRecord* EvsEnumerator::findUltrasonicsArrayById(
+        const std::string& ultrasonicsArrayId) {
+    auto recordIt = std::find_if(
+            sUltrasonicsArrayRecordList.begin(), sUltrasonicsArrayRecordList.end(),
+                    [&ultrasonicsArrayId](const UltrasonicsArrayRecord& record) {
+                            return ultrasonicsArrayId == record.desc.ultrasonicsArrayId;});
+
+    return (recordIt != sUltrasonicsArrayRecordList.end()) ? &*recordIt : nullptr;
+}
+
 Return<void> EvsEnumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) {
-    hidl_vec<UltrasonicsArrayDesc> ultrasonicsArrayDesc;
-    _hidl_cb(ultrasonicsArrayDesc);
+    hidl_vec<UltrasonicsArrayDesc> desc;
+    desc.resize(sUltrasonicsArrayRecordList.size());
+
+    // Copy over desc from sUltrasonicsArrayRecordList.
+    for (auto p = std::make_pair(sUltrasonicsArrayRecordList.begin(), desc.begin());
+            p.first != sUltrasonicsArrayRecordList.end(); p.first++, p.second++) {
+        *p.second = p.first->desc;
+    }
+
+    // Send back the results
+    ALOGD("reporting %zu ultrasonics arrays available", desc.size());
+    _hidl_cb(desc);
+
+    // HIDL convention says we return Void if we sent our result back via callback
     return Void();
 }
 
-// TODO(b/148608401): Add default implementation with dummy data.
 Return<sp<IEvsUltrasonicsArray>> EvsEnumerator::openUltrasonicsArray(
         const hidl_string& ultrasonicsArrayId) {
-    (void)ultrasonicsArrayId;
-    sp<IEvsUltrasonicsArray> pEvsUltrasonicsArray;
-    return pEvsUltrasonicsArray;
+    // Find the named ultrasonic array.
+    UltrasonicsArrayRecord* pRecord = findUltrasonicsArrayById(ultrasonicsArrayId);
+
+    // Is this a recognized ultrasonic array id?
+    if (!pRecord) {
+        ALOGE("Requested ultrasonics array %s not found", ultrasonicsArrayId.c_str());
+        return nullptr;
+    }
+
+    // Has this ultrasonic array already been instantiated by another caller?
+    sp<EvsUltrasonicsArray> pActiveUltrasonicsArray = pRecord->activeInstance.promote();
+    if (pActiveUltrasonicsArray != nullptr) {
+        ALOGW("Killing previous ultrasonics array because of new caller");
+        closeUltrasonicsArray(pActiveUltrasonicsArray);
+    }
+
+    // Construct a ultrasonic array instance for the caller
+    pActiveUltrasonicsArray = EvsUltrasonicsArray::Create(ultrasonicsArrayId.c_str());
+    pRecord->activeInstance = pActiveUltrasonicsArray;
+    if (pActiveUltrasonicsArray == nullptr) {
+        ALOGE("Failed to allocate new EvsUltrasonicsArray object for %s\n",
+              ultrasonicsArrayId.c_str());
+    }
+
+    return pActiveUltrasonicsArray;
 }
 
-// TODO(b/148608401): Add default implementation with dummy data.
 Return<void> EvsEnumerator::closeUltrasonicsArray(
-        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray)  {
-    (void)evsUltrasonicsArray;
+        const sp<IEvsUltrasonicsArray>& pEvsUltrasonicsArray) {
+
+    if (pEvsUltrasonicsArray.get() == nullptr) {
+        ALOGE("Ignoring call to closeUltrasonicsArray with null ultrasonics array");
+        return Void();
+    }
+
+    // Get the ultrasonics array id so we can find it in our list.
+    std::string ultrasonicsArrayId;
+    pEvsUltrasonicsArray->getUltrasonicArrayInfo([&ultrasonicsArrayId](UltrasonicsArrayDesc desc) {
+        ultrasonicsArrayId.assign(desc.ultrasonicsArrayId);
+    });
+
+    // Find the named ultrasonics array
+    UltrasonicsArrayRecord* pRecord = findUltrasonicsArrayById(ultrasonicsArrayId);
+    if (!pRecord) {
+        ALOGE("Asked to close a ultrasonics array whose name isnt not found");
+        return Void();
+    }
+
+    sp<EvsUltrasonicsArray> pActiveUltrasonicsArray = pRecord->activeInstance.promote();
+
+    if (pActiveUltrasonicsArray.get() == nullptr) {
+        ALOGE("Somehow a ultrasonics array is being destroyed when the enumerator didn't know "
+              "one existed");
+    } else if (pActiveUltrasonicsArray != pEvsUltrasonicsArray) {
+        // This can happen if the ultrasonics array was aggressively reopened,
+        // orphaning this previous instance
+        ALOGW("Ignoring close of previously orphaned ultrasonics array - why did a client steal?");
+    } else {
+        // Drop the active ultrasonics array
+        pActiveUltrasonicsArray->forceShutdown();
+        pRecord->activeInstance = nullptr;
+    }
+
     return Void();
 }