Camera: Add 2.1 version of ICameraService and ICameraServiceCallback

The new interface is used to handle
onPhysicalCameraUnavailable/Available.

Test: /data/nativetest64/VtsHalCameraServiceV2_0TargetTest/VtsHalCameraServiceV2_0TargetTest
Bug: 148146086
Change-Id: Ic81686d2fb83d6e80d2b94202515b7bb5f286178
diff --git a/cameraservice/service/2.1/Android.bp b/cameraservice/service/2.1/Android.bp
new file mode 100644
index 0000000..a45b814
--- /dev/null
+++ b/cameraservice/service/2.1/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "[email protected]",
+    root: "android.frameworks",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICameraService.hal",
+        "ICameraServiceListener.hal",
+    ],
+    interfaces: [
+        "[email protected]",
+        "[email protected]",
+        "[email protected]",
+        "[email protected]",
+    ],
+    gen_java: false,
+}
diff --git a/cameraservice/service/2.1/ICameraService.hal b/cameraservice/service/2.1/ICameraService.hal
new file mode 100644
index 0000000..ca449e5
--- /dev/null
+++ b/cameraservice/service/2.1/ICameraService.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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 [email protected];
+
+import [email protected]::Status;
+import [email protected]::ICameraService;
+import [email protected]::CameraStatusAndId;
+import [email protected]::ICameraServiceListener;
+import [email protected]::PhysicalCameraStatusAndId;
+
+interface ICameraService extends @2.0::ICameraService {
+    /**
+     * Add listener for changes to camera device status.
+     *
+     * Identical to @2.0::ICameraService.addListener, except that:
+     *
+     * - The listener now contains an onPhysicalCameraStatusChanged function,
+     * which is called by the camera service when a physical camera backing a
+     * logical multi-camera becomes unavailable or available again.
+     * - The function returns a vector of the newer version of CameraStatusAndId
+     * which contains unavailable physical cameras if the specified camera is a
+     * logical multi-camera.
+     *
+     * @param listener the listener interface to be added. The cameraserver will
+     *         call callbacks on this interface when a camera device's status
+     *         changes.
+     * @return status Status code of the operation
+     * @return statuses a list of CameraStatusAndIds which stores the deviceIds,
+     *         their corresponding statuses, and the unavailable physical camera Ids
+     *         if the device is a logical multi-camera.
+     */
+    addListener_2_1(ICameraServiceListener listener)
+        generates (Status status, vec<CameraStatusAndId> statuses);
+};
diff --git a/cameraservice/service/2.1/ICameraServiceListener.hal b/cameraservice/service/2.1/ICameraServiceListener.hal
new file mode 100644
index 0000000..2c61a6a
--- /dev/null
+++ b/cameraservice/service/2.1/ICameraServiceListener.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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 [email protected];
+
+import [email protected];
+
+interface ICameraServiceListener extends @2.0::ICameraServiceListener {
+    /**
+     * Callback called by cameraservice when the status of a physical
+     * camera device backing a logical camera changes
+     *
+     * @param statusAndId the current device status of a physical camera device
+     *                    backing a logical camera.
+     */
+    oneway onPhysicalCameraStatusChanged(PhysicalCameraStatusAndId statusAndId);
+};
diff --git a/cameraservice/service/2.1/types.hal b/cameraservice/service/2.1/types.hal
new file mode 100644
index 0000000..dda1d30
--- /dev/null
+++ b/cameraservice/service/2.1/types.hal
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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 [email protected];
+
+import [email protected]::CameraDeviceStatus;
+import [email protected]::CameraStatusAndId;
+
+/**
+ * CameraStatusAndId:
+ *
+ * The camera Id and its corresponding CameraDeviceStatus
+ *
+ * This version extends the @2_0::CameraStatusAndId with the
+ * unavailPhysicalCameraIds field.
+ *
+ */
+struct CameraStatusAndId {
+    /**
+     * The definition of CameraStatusAndId from prior version.
+     */
+    @2.0::CameraStatusAndId v2_0;
+
+    /**
+     * The physical cameras that are unavailable to use (via physical streams)
+     * for this logical multi-camera.
+     */
+    vec<string> unavailPhysicalCameraIds;
+};
+
+/**
+ * PhysicalCameraStatusAndId:
+ *
+ * The physical camera id backing a logical multi-camera, and its
+ * corresponding CameraDeviceStatus.
+ */
+struct PhysicalCameraStatusAndId {
+    CameraDeviceStatus deviceStatus;
+    string cameraId;
+    string physicalCameraId;
+};
diff --git a/cameraservice/vts/functional/Android.bp b/cameraservice/vts/functional/Android.bp
index 2c68b99..79c6885 100644
--- a/cameraservice/vts/functional/Android.bp
+++ b/cameraservice/vts/functional/Android.bp
@@ -23,6 +23,7 @@
         "[email protected]",
         "[email protected]",
         "[email protected]",
+        "[email protected]",
         "[email protected]",
         "libfmq",
     ],
diff --git a/cameraservice/vts/functional/VtsHalCameraServiceV2_0TargetTest.cpp b/cameraservice/vts/functional/VtsHalCameraServiceV2_0TargetTest.cpp
index b313750..8c814d4 100644
--- a/cameraservice/vts/functional/VtsHalCameraServiceV2_0TargetTest.cpp
+++ b/cameraservice/vts/functional/VtsHalCameraServiceV2_0TargetTest.cpp
@@ -19,6 +19,7 @@
 
 #include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
 #include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.1/ICameraService.h>
 #include <system/camera_metadata.h>
 #include <system/graphics.h>
 
@@ -37,6 +38,7 @@
 #include <algorithm>
 #include <mutex>
 #include <string>
+#include <unordered_set>
 #include <vector>
 
 #include <media/NdkImageReader.h>
@@ -66,6 +68,7 @@
 using android::frameworks::cameraservice::service::V2_0::CameraStatusAndId;
 using android::frameworks::cameraservice::service::V2_0::ICameraService;
 using android::frameworks::cameraservice::service::V2_0::ICameraServiceListener;
+using android::frameworks::cameraservice::service::V2_1::PhysicalCameraStatusAndId;
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
 using android::hardware::Return;
@@ -100,6 +103,57 @@
     };
 };
 
+class CameraServiceListener2_1
+    : public android::frameworks::cameraservice::service::V2_1::ICameraServiceListener {
+    std::map<hidl_string, CameraDeviceStatus> mCameraStatuses;
+    std::map<hidl_string, std::set<hidl_string>> mUnavailablePhysicalCameras;
+    mutable Mutex mLock;
+
+   public:
+    virtual ~CameraServiceListener2_1(){};
+
+    virtual Return<void> onStatusChanged(const CameraStatusAndId& statusAndId) override {
+        Mutex::Autolock l(mLock);
+        mCameraStatuses[statusAndId.cameraId] = statusAndId.deviceStatus;
+        return Void();
+    };
+
+    virtual Return<void> onPhysicalCameraStatusChanged(
+        const PhysicalCameraStatusAndId& statusAndId) override {
+        Mutex::Autolock l(mLock);
+        ALOGI("%s: Physical camera %s : %s status changed to %d", __FUNCTION__,
+              statusAndId.cameraId.c_str(), statusAndId.physicalCameraId.c_str(),
+              statusAndId.deviceStatus);
+
+        EXPECT_NE(mCameraStatuses.find(statusAndId.cameraId), mCameraStatuses.end());
+        EXPECT_EQ(mCameraStatuses[statusAndId.cameraId], CameraDeviceStatus::STATUS_PRESENT);
+
+        if (statusAndId.deviceStatus == CameraDeviceStatus::STATUS_NOT_PRESENT) {
+            auto res = mUnavailablePhysicalCameras[statusAndId.cameraId].emplace(
+                statusAndId.physicalCameraId);
+            EXPECT_TRUE(res.second);
+        } else {
+            auto res = mUnavailablePhysicalCameras[statusAndId.cameraId].erase(
+                statusAndId.physicalCameraId);
+            EXPECT_EQ(res, 1);
+        }
+        return Void();
+    };
+
+    void initializeStatuses(
+        const hidl_vec<android::frameworks::cameraservice::service::V2_1::CameraStatusAndId>&
+            statuses) {
+        Mutex::Autolock l(mLock);
+
+        for (auto& status : statuses) {
+            mCameraStatuses[status.v2_0.cameraId] = status.v2_0.deviceStatus;
+            for (auto& physicalId : status.unavailPhysicalCameraIds) {
+                mUnavailablePhysicalCameras[status.v2_0.cameraId].emplace(physicalId);
+            }
+        }
+    }
+};
+
 // ICameraDeviceCallback implementation
 class CameraDeviceCallbacks : public ICameraDeviceCallback {
    public:
@@ -233,6 +287,12 @@
    public:
     void SetUp() override {
         cs = ICameraService::getService(GetParam());
+
+        auto castResult =
+            android::frameworks::cameraservice::service::V2_1::ICameraService::castFrom(cs);
+        if (castResult.isOk()) {
+            cs2_1 = castResult;
+        }
     }
 
     void TearDown() override {}
@@ -302,6 +362,7 @@
     }
 
     sp<ICameraService> cs = nullptr;
+    sp<android::frameworks::cameraservice::service::V2_1::ICameraService> cs2_1 = nullptr;
 };
 
 // Basic HIDL calls for ICameraService
@@ -317,7 +378,6 @@
     EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
     for (const auto& it : cameraStatuses) {
         CameraMetadata rawMetadata;
-        listener->onStatusChanged(it);
         if (it.deviceStatus != CameraDeviceStatus::STATUS_PRESENT) {
             continue;
         }
@@ -451,6 +511,66 @@
     EXPECT_TRUE(ret.isOk() && ret == Status::NO_ERROR);
 }
 
+TEST_P(VtsHalCameraServiceV2_0TargetTest, CameraServiceListener2_1Test) {
+    sp<CameraServiceListener2_1> listener2_1(new CameraServiceListener2_1());
+    hidl_vec<android::frameworks::cameraservice::service::V2_1::CameraStatusAndId>
+        cameraStatuses2_1{};
+    Status status = Status::NO_ERROR;
+
+    if (cs2_1 == nullptr) return;
+
+    auto remoteRet = cs2_1->addListener_2_1(
+        listener2_1, [&status, &cameraStatuses2_1](Status s, auto& retStatuses) {
+            status = s;
+            cameraStatuses2_1 = retStatuses;
+        });
+    EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
+    listener2_1->initializeStatuses(cameraStatuses2_1);
+
+    for (const auto& it : cameraStatuses2_1) {
+        CameraMetadata rawMetadata;
+        remoteRet = cs2_1->getCameraCharacteristics(
+            it.v2_0.cameraId, [&status, &rawMetadata](auto s, const hidl_vec<uint8_t>& metadata) {
+                status = s;
+                bool cStatus = convertFromHidlCloned(metadata, &rawMetadata);
+                EXPECT_TRUE(cStatus);
+            });
+        EXPECT_TRUE(remoteRet.isOk() && status == Status::NO_ERROR);
+        EXPECT_FALSE(rawMetadata.isEmpty());
+        bool isLogicalCamera = doesCapabilityExist(
+            rawMetadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA);
+        if (!isLogicalCamera) {
+            EXPECT_TRUE(it.unavailPhysicalCameraIds.size() == 0);
+            continue;
+        }
+        camera_metadata_entry entry = rawMetadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+        EXPECT_GT(entry.count, 0);
+
+        std::unordered_set<std::string> validPhysicalIds;
+        const uint8_t* ids = entry.data.u8;
+        size_t start = 0;
+        for (size_t i = 0; i < entry.count; i++) {
+            if (ids[i] == '\0') {
+                if (start != i) {
+                    std::string currentId(reinterpret_cast<const char*>(ids + start));
+                    validPhysicalIds.emplace(currentId);
+                }
+                start = i + 1;
+            }
+        }
+
+        std::unordered_set<std::string> unavailablePhysicalIds(it.unavailPhysicalCameraIds.begin(),
+                                                               it.unavailPhysicalCameraIds.end());
+        EXPECT_EQ(unavailablePhysicalIds.size(), it.unavailPhysicalCameraIds.size());
+        for (auto& unavailablePhysicalId : unavailablePhysicalIds) {
+            EXPECT_NE(validPhysicalIds.find(unavailablePhysicalId), validPhysicalIds.end());
+        }
+    }
+
+    auto remoteStatus = cs2_1->removeListener(listener2_1);
+    EXPECT_TRUE(remoteStatus.isOk() && remoteStatus == Status::NO_ERROR);
+}
+
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, VtsHalCameraServiceV2_0TargetTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraService::descriptor)),
diff --git a/current.txt b/current.txt
index 6be8b44..03b0185 100644
--- a/current.txt
+++ b/current.txt
@@ -31,3 +31,8 @@
 6c7a38d5cff74dc0644514debf7f943ead81b33aa5aa59756e4f09f6e7f87a22 [email protected]::types
 f4173a30f4d36e12871fe5072197dc1b9ca705f8c99b031186ca24f68bb84594 [email protected]::IStats
 d9c951c12923ae3962e6947fe008f4c372f117182a4c3aaf483d9b3748af0bcc [email protected]::types
+
+# Framework HALs released in Android R
+f5bcda0e55d2cf2a8f9d5ebc436d6f967e210835dc4ac4ea014cd12bc476639e [email protected]::ICameraService
+392d98ed528ebd5ee14c9e65ef633cbbeeb33c74e5ab1be2cfd8a865ac4c9c86 [email protected]::ICameraServiceListener
+aedecd4d47697f0cc2d62e46ff7442bab2c4571237719f44b222bfdfcbd30d92 [email protected]::types