Camera: Fill out vndk implementation for physical camera callbacks

Also fixed missing implementation of Camera availability callbacks for
ExtendedAvailabilityCallback.

Test: Camera CTS, and vndk test
Bug: 148146086
Change-Id: I557d6db3900b2346b7bc7e12cd946bc4c2dc4076
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 22e9578..dc7f88a 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -48,6 +48,6 @@
     init_rc: ["cameraserver.rc"],
 
     vintf_fragments: [
-        "manifest_android.frameworks.cameraservice.service@2.0.xml",
+        "manifest_android.frameworks.cameraservice.service@2.1.xml",
     ],
 }
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml
similarity index 90%
rename from camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml
rename to camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml
index 601c717..5a15b35 100644
--- a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml
+++ b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml
@@ -2,7 +2,7 @@
     <hal>
         <name>android.frameworks.cameraservice.service</name>
         <transport>hwbinder</transport>
-        <version>2.0</version>
+        <version>2.1</version>
         <interface>
             <name>ICameraService</name>
             <instance>default</instance>
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 56f209c..7ba82c1 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -123,6 +123,7 @@
         "android.frameworks.cameraservice.device@2.0",
         "android.frameworks.cameraservice.common@2.0",
         "android.frameworks.cameraservice.service@2.0",
+        "android.frameworks.cameraservice.service@2.1",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
@@ -140,9 +141,12 @@
 }
 
 cc_test {
-    name: "AImageReaderVendorTest",
+    name: "ACameraNdkVendorTest",
     vendor: true,
-    srcs: ["ndk_vendor/tests/AImageReaderVendorTest.cpp"],
+    srcs: [
+        "ndk_vendor/tests/AImageReaderVendorTest.cpp",
+        "ndk_vendor/tests/ACameraManagerTest.cpp",
+    ],
     shared_libs: [
         "libcamera2ndk_vendor",
         "libcamera_metadata",
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 4870265..f408b6a 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -130,6 +130,11 @@
         mCameraService->addListener(mCameraServiceListener, &cameraStatuses);
         for (auto& c : cameraStatuses) {
             onStatusChangedLocked(c.status, c.cameraId);
+
+            for (auto& unavailablePhysicalId : c.unavailablePhysicalIds) {
+                onStatusChangedLocked(hardware::ICameraServiceListener::STATUS_NOT_PRESENT,
+                        c.cameraId, unavailablePhysicalId);
+            }
         }
 
         // setup vendor tags
@@ -200,9 +205,7 @@
 
 void CameraManagerGlobal::registerExtendedAvailabilityCallback(
         const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
-    Mutex::Autolock _l(mLock);
-    Callback cb(callback);
-    mCallbacks.insert(cb);
+    return registerAvailCallback<ACameraManager_ExtendedAvailabilityCallbacks>(callback);
 }
 
 void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
@@ -214,6 +217,18 @@
 
 void CameraManagerGlobal::registerAvailabilityCallback(
         const ACameraManager_AvailabilityCallbacks *callback) {
+    return registerAvailCallback<ACameraManager_AvailabilityCallbacks>(callback);
+}
+
+void CameraManagerGlobal::unregisterAvailabilityCallback(
+        const ACameraManager_AvailabilityCallbacks *callback) {
+    Mutex::Autolock _l(mLock);
+    Callback cb(callback);
+    mCallbacks.erase(cb);
+}
+
+template<class T>
+void CameraManagerGlobal::registerAvailCallback(const T *callback) {
     Mutex::Autolock _l(mLock);
     Callback cb(callback);
     auto pair = mCallbacks.insert(cb);
@@ -227,24 +242,33 @@
             if (!pair.second.supportsHAL3) {
                 continue;
             }
+
+            // Camera available/unavailable callback
             sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
-            ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
-                    callback->onCameraAvailable : callback->onCameraUnavailable;
-            msg->setPointer(kCallbackFpKey, (void *) cb);
-            msg->setPointer(kContextKey, callback->context);
+            ACameraManager_AvailabilityCallback cbFunc = isStatusAvailable(status) ?
+                    cb.mAvailable : cb.mUnavailable;
+            msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+            msg->setPointer(kContextKey, cb.mContext);
             msg->setString(kCameraIdKey, AString(cameraId));
             msg->post();
+
+            // Physical camera unavailable callback
+            std::set<String8> unavailablePhysicalCameras =
+                    pair.second.getUnavailablePhysicalIds();
+            for (const auto& physicalCameraId : unavailablePhysicalCameras) {
+                sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+                ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
+                        cb.mPhysicalCamUnavailable;
+                msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+                msg->setPointer(kContextKey, cb.mContext);
+                msg->setString(kCameraIdKey, AString(cameraId));
+                msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId));
+                msg->post();
+            }
         }
     }
 }
 
-void CameraManagerGlobal::unregisterAvailabilityCallback(
-        const ACameraManager_AvailabilityCallbacks *callback) {
-    Mutex::Autolock _l(mLock);
-    Callback cb(callback);
-    mCallbacks.erase(cb);
-}
-
 bool CameraManagerGlobal::supportsCamera2ApiLocked(const String8 &cameraId) {
     bool camera2Support = false;
     auto cs = getCameraServiceLocked();
@@ -550,6 +574,11 @@
     return count > 0;
 }
 
+std::set<String8> CameraManagerGlobal::StatusAndHAL3Support::getUnavailablePhysicalIds() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return unavailablePhysicalIds;
+}
+
 } // namespace acam
 } // namespace android
 
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 98cd934..836e037 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -70,6 +70,9 @@
     const char*                  kCameraServiceName      = "media.camera";
     Mutex                        mLock;
 
+    template<class T>
+    void registerAvailCallback(const T *callback);
+
     class DeathNotifier : public IBinder::DeathRecipient {
       public:
         explicit DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
@@ -222,6 +225,7 @@
         bool removeUnavailablePhysicalId(const String8& physicalCameraId);
         int32_t getStatus();
         void updateStatus(int32_t newStatus);
+        std::set<String8> getUnavailablePhysicalIds();
     };
 
     // Map camera_id -> status
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index 70c887a..a95fe2a 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -36,13 +36,13 @@
 namespace android {
 namespace acam {
 
-using frameworks::cameraservice::service::V2_0::CameraStatusAndId;
 using frameworks::cameraservice::common::V2_0::ProviderIdAndVendorTagSections;
 using android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
 using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
 
 // Static member definitions
 const char* CameraManagerGlobal::kCameraIdKey   = "CameraId";
+const char* CameraManagerGlobal::kPhysicalCameraIdKey   = "PhysicalCameraId";
 const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
 const char* CameraManagerGlobal::kContextKey    = "CallbackContext";
 Mutex                CameraManagerGlobal::sLock;
@@ -258,9 +258,9 @@
         if (mCameraServiceListener == nullptr) {
             mCameraServiceListener = new CameraServiceListener(this);
         }
-        hidl_vec<CameraStatusAndId> cameraStatuses{};
+        hidl_vec<frameworks::cameraservice::service::V2_1::CameraStatusAndId> cameraStatuses{};
         Status status = Status::NO_ERROR;
-        auto remoteRet = mCameraService->addListener(mCameraServiceListener,
+        auto remoteRet = mCameraService->addListener_2_1(mCameraServiceListener,
                                                      [&status, &cameraStatuses](Status s,
                                                                                 auto &retStatuses) {
                                                          status = s;
@@ -277,7 +277,15 @@
         }
 
         for (auto& c : cameraStatuses) {
-            onStatusChangedLocked(c);
+            onStatusChangedLocked(c.v2_0);
+
+            for (auto& unavailablePhysicalId : c.unavailPhysicalCameraIds) {
+                PhysicalCameraStatusAndId statusAndId;
+                statusAndId.deviceStatus = CameraDeviceStatus::STATUS_NOT_PRESENT;
+                statusAndId.cameraId = c.v2_0.cameraId;
+                statusAndId.physicalCameraId = unavailablePhysicalId;
+                onStatusChangedLocked(statusAndId);
+            }
         }
     }
     return mCameraService;
@@ -293,7 +301,7 @@
         for (auto& pair : cm->mDeviceStatusMap) {
             CameraStatusAndId cameraStatusAndId;
             cameraStatusAndId.cameraId = pair.first;
-            cameraStatusAndId.deviceStatus = pair.second;
+            cameraStatusAndId.deviceStatus = pair.second.getStatus();
             cm->onStatusChangedLocked(cameraStatusAndId);
         }
         cm->mCameraService.clear();
@@ -303,24 +311,7 @@
 
 void CameraManagerGlobal::registerAvailabilityCallback(
         const ACameraManager_AvailabilityCallbacks *callback) {
-    Mutex::Autolock _l(mLock);
-    Callback cb(callback);
-    auto pair = mCallbacks.insert(cb);
-    // Send initial callbacks if callback is newly registered
-    if (pair.second) {
-        for (auto& pair : mDeviceStatusMap) {
-            const hidl_string& cameraId = pair.first;
-            CameraDeviceStatus status = pair.second;
-
-            sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
-            ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
-                    callback->onCameraAvailable : callback->onCameraUnavailable;
-            msg->setPointer(kCallbackFpKey, (void *) cb);
-            msg->setPointer(kContextKey, callback->context);
-            msg->setString(kCameraIdKey, AString(cameraId.c_str()));
-            msg->post();
-        }
-    }
+    return registerAvailCallback<ACameraManager_AvailabilityCallbacks>(callback);
 }
 
 void CameraManagerGlobal::unregisterAvailabilityCallback(
@@ -330,14 +321,63 @@
     mCallbacks.erase(cb);
 }
 
+void CameraManagerGlobal::registerExtendedAvailabilityCallback(
+        const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+    return registerAvailCallback<ACameraManager_ExtendedAvailabilityCallbacks>(callback);
+}
+
+void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
+        const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+    Mutex::Autolock _l(mLock);
+    Callback cb(callback);
+    mCallbacks.erase(cb);
+}
+
+template <class T>
+void CameraManagerGlobal::registerAvailCallback(const T *callback) {
+    Mutex::Autolock _l(mLock);
+    Callback cb(callback);
+    auto pair = mCallbacks.insert(cb);
+    // Send initial callbacks if callback is newly registered
+    if (pair.second) {
+        for (auto& pair : mDeviceStatusMap) {
+            const hidl_string& cameraId = pair.first;
+            CameraDeviceStatus status = pair.second.getStatus();
+
+            // Camera available/unavailable callback
+            sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+            ACameraManager_AvailabilityCallback cbFunc = isStatusAvailable(status) ?
+                    cb.mAvailable : cb.mUnavailable;
+            msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+            msg->setPointer(kContextKey, cb.mContext);
+            msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+            msg->post();
+
+            // Physical camera unavailable callback
+            std::set<hidl_string> unavailPhysicalIds = pair.second.getUnavailablePhysicalIds();
+            for (const auto& physicalCameraId : unavailPhysicalIds) {
+                sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+                ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
+                        cb.mPhysicalCamUnavailable;
+                msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+                msg->setPointer(kContextKey, cb.mContext);
+                msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+                msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
+                msg->post();
+            }
+        }
+    }
+}
+
 void CameraManagerGlobal::getCameraIdList(std::vector<hidl_string>* cameraIds) {
     // Ensure that we have initialized/refreshed the list of available devices
     auto cs = getCameraService();
     Mutex::Autolock _l(mLock);
 
     for(auto& deviceStatus : mDeviceStatusMap) {
-        if (deviceStatus.second == CameraDeviceStatus::STATUS_NOT_PRESENT ||
-                deviceStatus.second == CameraDeviceStatus::STATUS_ENUMERATING) {
+        CameraDeviceStatus status = deviceStatus.second.getStatus();
+        if (status == CameraDeviceStatus::STATUS_NOT_PRESENT ||
+                status == CameraDeviceStatus::STATUS_ENUMERATING) {
             continue;
         }
         cameraIds->push_back(deviceStatus.first);
@@ -391,6 +431,35 @@
             (*cb)(context, cameraId.c_str());
             break;
         }
+        case kWhatSendSinglePhysicalCameraCallback:
+        {
+            ACameraManager_PhysicalCameraAvailabilityCallback cb;
+            void* context;
+            AString cameraId;
+            AString physicalCameraId;
+            bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+            if (!found) {
+                ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+                return;
+            }
+            found = msg->findPointer(kContextKey, &context);
+            if (!found) {
+                ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+                return;
+            }
+            found = msg->findString(kCameraIdKey, &cameraId);
+            if (!found) {
+                ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+                return;
+            }
+            found = msg->findString(kPhysicalCameraIdKey, &physicalCameraId);
+            if (!found) {
+                ALOGE("%s: Cannot find physical camera ID!", __FUNCTION__);
+                return;
+            }
+            (*cb)(context, cameraId.c_str(), physicalCameraId.c_str());
+            break;
+        }
         default:
             ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
             break;
@@ -426,7 +495,7 @@
     bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
     CameraDeviceStatus oldStatus = firstStatus ?
             status : // first status
-            mDeviceStatusMap[cameraId];
+            mDeviceStatusMap[cameraId].getStatus();
 
     if (!firstStatus &&
             isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
@@ -435,7 +504,7 @@
     }
 
     // Iterate through all registered callbacks
-    mDeviceStatusMap[cameraId] = status;
+    mDeviceStatusMap[cameraId].updateStatus(status);
     for (auto cb : mCallbacks) {
         sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
         ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
@@ -450,6 +519,98 @@
     }
 }
 
+hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged(
+        const PhysicalCameraStatusAndId &statusAndId) {
+    sp<CameraManagerGlobal> cm = mCameraManager.promote();
+    if (cm != nullptr) {
+        cm->onStatusChanged(statusAndId);
+    } else {
+        ALOGE("Cannot deliver status change. Global camera manager died");
+    }
+    return Void();
+}
+
+void CameraManagerGlobal::onStatusChanged(
+        const PhysicalCameraStatusAndId &statusAndId) {
+    Mutex::Autolock _l(mLock);
+    onStatusChangedLocked(statusAndId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+        const PhysicalCameraStatusAndId &statusAndId) {
+    hidl_string cameraId = statusAndId.cameraId;
+    hidl_string physicalCameraId = statusAndId.physicalCameraId;
+    CameraDeviceStatus status = statusAndId.deviceStatus;
+    if (!validStatus(status)) {
+        ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+        return;
+    }
+
+    auto logicalStatus = mDeviceStatusMap.find(cameraId);
+    if (logicalStatus == mDeviceStatusMap.end()) {
+        ALOGE("%s: Physical camera id %s status change on a non-present id %s",
+                __FUNCTION__, physicalCameraId.c_str(), cameraId.c_str());
+        return;
+    }
+    CameraDeviceStatus logicalCamStatus = mDeviceStatusMap[cameraId].getStatus();
+    if (logicalCamStatus != CameraDeviceStatus::STATUS_PRESENT &&
+            logicalCamStatus != CameraDeviceStatus::STATUS_NOT_AVAILABLE) {
+        ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
+                __FUNCTION__, physicalCameraId.c_str(), status, logicalCamStatus);
+        return;
+    }
+
+    bool updated = false;
+    if (status == CameraDeviceStatus::STATUS_PRESENT) {
+        updated = mDeviceStatusMap[cameraId].removeUnavailablePhysicalId(physicalCameraId);
+    } else {
+        updated = mDeviceStatusMap[cameraId].addUnavailablePhysicalId(physicalCameraId);
+    }
+
+    // Iterate through all registered callbacks
+    if (updated) {
+        for (auto cb : mCallbacks) {
+            sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+            ACameraManager_PhysicalCameraAvailabilityCallback cbFp = isStatusAvailable(status) ?
+                    cb.mPhysicalCamAvailable : cb.mPhysicalCamUnavailable;
+            msg->setPointer(kCallbackFpKey, (void *) cbFp);
+            msg->setPointer(kContextKey, cb.mContext);
+            msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+            msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
+            msg->post();
+        }
+    }
+}
+
+CameraDeviceStatus CameraManagerGlobal::CameraStatus::getStatus() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return status;
+}
+
+void CameraManagerGlobal::CameraStatus::updateStatus(CameraDeviceStatus newStatus) {
+    std::lock_guard<std::mutex> lock(mLock);
+    status = newStatus;
+}
+
+bool CameraManagerGlobal::CameraStatus::addUnavailablePhysicalId(
+        const hidl_string& physicalCameraId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    auto result = unavailablePhysicalIds.insert(physicalCameraId);
+    return result.second;
+}
+
+bool CameraManagerGlobal::CameraStatus::removeUnavailablePhysicalId(
+        const hidl_string& physicalCameraId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    auto count = unavailablePhysicalIds.erase(physicalCameraId);
+    return count > 0;
+}
+
+std::set<hidl_string> CameraManagerGlobal::CameraStatus::getUnavailablePhysicalIds() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return unavailablePhysicalIds;
+}
+
 } // namespace acam
 } // namespace android
 
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 2c62d44..36c8e2b 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -21,6 +21,8 @@
 
 #include <android-base/parseint.h>
 #include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.1/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.1/ICameraServiceListener.h>
 
 #include <CameraMetadata.h>
 #include <utils/StrongPointer.h>
@@ -36,9 +38,10 @@
 namespace android {
 namespace acam {
 
-using ICameraService = frameworks::cameraservice::service::V2_0::ICameraService;
+using ICameraService = frameworks::cameraservice::service::V2_1::ICameraService;
 using CameraDeviceStatus = frameworks::cameraservice::service::V2_0::CameraDeviceStatus;
-using ICameraServiceListener = frameworks::cameraservice::service::V2_0::ICameraServiceListener;
+using ICameraServiceListener = frameworks::cameraservice::service::V2_1::ICameraServiceListener;
+using PhysicalCameraStatusAndId = frameworks::cameraservice::service::V2_1::PhysicalCameraStatusAndId;
 using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
 using Status = frameworks::cameraservice::common::V2_0::Status;
 using VendorTagSection = frameworks::cameraservice::common::V2_0::VendorTagSection;
@@ -65,9 +68,9 @@
             const ACameraManager_AvailabilityCallbacks *callback);
 
     void registerExtendedAvailabilityCallback(
-            const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+            const ACameraManager_ExtendedAvailabilityCallbacks* callback);
     void unregisterExtendedAvailabilityCallback(
-            const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+            const ACameraManager_ExtendedAvailabilityCallbacks* callback);
 
     /**
      * Return camera IDs that support camera2
@@ -94,6 +97,8 @@
         explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
         android::hardware::Return<void> onStatusChanged(
             const CameraStatusAndId &statusAndId) override;
+        android::hardware::Return<void> onPhysicalCameraStatusChanged(
+            const PhysicalCameraStatusAndId &statusAndId) override;
 
       private:
         const wp<CameraManagerGlobal> mCameraManager;
@@ -105,11 +110,25 @@
         explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
             mAvailable(callback->onCameraAvailable),
             mUnavailable(callback->onCameraUnavailable),
+            mAccessPriorityChanged(nullptr),
+            mPhysicalCamAvailable(nullptr),
+            mPhysicalCamUnavailable(nullptr),
             mContext(callback->context) {}
 
+        explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
+            mAvailable(callback->availabilityCallbacks.onCameraAvailable),
+            mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
+            mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+            mPhysicalCamAvailable(callback->onPhysicalCameraAvailable),
+            mPhysicalCamUnavailable(callback->onPhysicalCameraUnavailable),
+            mContext(callback->availabilityCallbacks.context) {}
+
         bool operator == (const Callback& other) const {
             return (mAvailable == other.mAvailable &&
                     mUnavailable == other.mUnavailable &&
+                    mAccessPriorityChanged == other.mAccessPriorityChanged &&
+                    mPhysicalCamAvailable == other.mPhysicalCamAvailable &&
+                    mPhysicalCamUnavailable == other.mPhysicalCamUnavailable &&
                     mContext == other.mContext);
         }
         bool operator != (const Callback& other) const {
@@ -119,6 +138,12 @@
             if (*this == other) return false;
             if (mContext != other.mContext) return mContext < other.mContext;
             if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
+            if (mAccessPriorityChanged != other.mAccessPriorityChanged)
+                    return mAccessPriorityChanged < other.mAccessPriorityChanged;
+            if (mPhysicalCamAvailable != other.mPhysicalCamAvailable)
+                    return mPhysicalCamAvailable < other.mPhysicalCamAvailable;
+            if (mPhysicalCamUnavailable != other.mPhysicalCamUnavailable)
+                    return mPhysicalCamUnavailable < other.mPhysicalCamUnavailable;
             return mUnavailable < other.mUnavailable;
         }
         bool operator > (const Callback& other) const {
@@ -126,15 +151,20 @@
         }
         ACameraManager_AvailabilityCallback mAvailable;
         ACameraManager_AvailabilityCallback mUnavailable;
+        ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
+        ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamAvailable;
+        ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamUnavailable;
         void*                               mContext;
     };
     std::set<Callback> mCallbacks;
 
     // definition of handler and message
     enum {
-        kWhatSendSingleCallback
+        kWhatSendSingleCallback,
+        kWhatSendSinglePhysicalCameraCallback,
     };
     static const char* kCameraIdKey;
+    static const char* kPhysicalCameraIdKey;
     static const char* kCallbackFpKey;
     static const char* kContextKey;
     class CallbackHandler : public AHandler {
@@ -147,6 +177,8 @@
 
     void onStatusChanged(const CameraStatusAndId &statusAndId);
     void onStatusChangedLocked(const CameraStatusAndId &statusAndId);
+    void onStatusChanged(const PhysicalCameraStatusAndId &statusAndId);
+    void onStatusChangedLocked(const PhysicalCameraStatusAndId &statusAndId);
     bool setupVendorTags();
 
     // Utils for status
@@ -174,8 +206,27 @@
         }
     };
 
+    struct CameraStatus {
+      private:
+        CameraDeviceStatus status = CameraDeviceStatus::STATUS_NOT_PRESENT;
+        mutable std::mutex mLock;
+        std::set<hidl_string> unavailablePhysicalIds;
+      public:
+        CameraStatus(CameraDeviceStatus st): status(st) { };
+        CameraStatus() = default;
+
+        bool addUnavailablePhysicalId(const hidl_string& physicalCameraId);
+        bool removeUnavailablePhysicalId(const hidl_string& physicalCameraId);
+        CameraDeviceStatus getStatus();
+        void updateStatus(CameraDeviceStatus newStatus);
+        std::set<hidl_string> getUnavailablePhysicalIds();
+    };
+
+    template <class T>
+    void registerAvailCallback(const T *callback);
+
     // Map camera_id -> status
-    std::map<hidl_string, CameraDeviceStatus, CameraIdComparator> mDeviceStatusMap;
+    std::map<hidl_string, CameraStatus, CameraIdComparator> mDeviceStatusMap;
 
     // For the singleton instance
     static Mutex sLock;
diff --git a/camera/ndk/ndk_vendor/tests/ACameraManagerTest.cpp b/camera/ndk/ndk_vendor/tests/ACameraManagerTest.cpp
new file mode 100644
index 0000000..a20a290
--- /dev/null
+++ b/camera/ndk/ndk_vendor/tests/ACameraManagerTest.cpp
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ACameraManagerTest"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include <mutex>
+#include <set>
+#include <string>
+
+#include <utils/Log.h>
+#include <camera/NdkCameraError.h>
+#include <camera/NdkCameraManager.h>
+
+namespace {
+
+class CameraServiceListener {
+  public:
+    typedef std::set<std::pair<std::string, std::string>> StringPairSet;
+
+    static void onAvailable(void* obj, const char* cameraId) {
+        ALOGV("Camera %s onAvailable", cameraId);
+        if (obj == nullptr) {
+            return;
+        }
+        CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+        std::lock_guard<std::mutex> lock(thiz->mMutex);
+        thiz->mOnAvailableCount++;
+        thiz->mAvailableMap[cameraId] = true;
+        return;
+    }
+
+    static void onUnavailable(void* obj, const char* cameraId) {
+        ALOGV("Camera %s onUnavailable", cameraId);
+        if (obj == nullptr) {
+            return;
+        }
+        CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+        std::lock_guard<std::mutex> lock(thiz->mMutex);
+        thiz->mOnUnavailableCount++;
+        thiz->mAvailableMap[cameraId] = false;
+        return;
+    }
+
+    static void onCameraAccessPrioritiesChanged(void* /*obj*/) {
+        return;
+    }
+
+    static void onPhysicalCameraAvailable(void* obj, const char* cameraId,
+            const char* physicalCameraId) {
+        ALOGV("Camera %s : %s onAvailable", cameraId, physicalCameraId);
+        if (obj == nullptr) {
+            return;
+        }
+        CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+        std::lock_guard<std::mutex> lock(thiz->mMutex);
+        thiz->mOnPhysicalCameraAvailableCount++;
+        return;
+    }
+
+    static void onPhysicalCameraUnavailable(void* obj, const char* cameraId,
+            const char* physicalCameraId) {
+        ALOGV("Camera %s : %s onUnavailable", cameraId, physicalCameraId);
+        if (obj == nullptr) {
+            return;
+        }
+        CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+        std::lock_guard<std::mutex> lock(thiz->mMutex);
+        thiz->mUnavailablePhysicalCameras.emplace(cameraId, physicalCameraId);
+        return;
+    }
+
+    void resetCount() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mOnAvailableCount = 0;
+        mOnUnavailableCount = 0;
+        mOnPhysicalCameraAvailableCount = 0;
+        mUnavailablePhysicalCameras.clear();
+        return;
+    }
+
+    int getAvailableCount() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mOnAvailableCount;
+    }
+
+    int getUnavailableCount() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mOnUnavailableCount;
+    }
+
+    int getPhysicalCameraAvailableCount() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mOnPhysicalCameraAvailableCount;
+    }
+
+    StringPairSet getUnavailablePhysicalCameras() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mUnavailablePhysicalCameras;
+    }
+
+    bool isAvailable(const char* cameraId) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        if (mAvailableMap.count(cameraId) == 0) {
+            return false;
+        }
+        return mAvailableMap[cameraId];
+    }
+
+  private:
+    std::mutex mMutex;
+    int mOnAvailableCount = 0;
+    int mOnUnavailableCount = 0;
+    int mOnPhysicalCameraAvailableCount = 0;
+    std::map<std::string, bool> mAvailableMap;
+    StringPairSet mUnavailablePhysicalCameras;
+};
+
+class ACameraManagerTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        mCameraManager = ACameraManager_create();
+        if (mCameraManager == nullptr) {
+            ALOGE("Failed to create ACameraManager.");
+            return;
+        }
+
+        camera_status_t ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
+        if (ret != ACAMERA_OK) {
+            ALOGE("Failed to get cameraIdList: ret=%d", ret);
+            return;
+        }
+        if (mCameraIdList->numCameras < 1) {
+            ALOGW("Device has no camera on board.");
+            return;
+        }
+    }
+    void TearDown() override {
+        // Destroy camera manager
+        if (mCameraIdList) {
+            ACameraManager_deleteCameraIdList(mCameraIdList);
+            mCameraIdList = nullptr;
+        }
+        if (mCameraManager) {
+            ACameraManager_delete(mCameraManager);
+            mCameraManager = nullptr;
+        }
+    }
+
+    // Camera manager
+    ACameraManager* mCameraManager = nullptr;
+    ACameraIdList* mCameraIdList = nullptr;
+    CameraServiceListener mAvailabilityListener;
+    ACameraManager_ExtendedAvailabilityCallbacks mCbs = {
+        {
+            &mAvailabilityListener,
+                CameraServiceListener::onAvailable,
+                CameraServiceListener::onUnavailable
+        },
+        CameraServiceListener::onCameraAccessPrioritiesChanged,
+        CameraServiceListener::onPhysicalCameraAvailable,
+        CameraServiceListener::onPhysicalCameraUnavailable,
+        {}
+    };
+};
+
+TEST_F(ACameraManagerTest, testCameraManagerExtendedAvailabilityCallbacks) {
+    camera_status_t ret = ACameraManager_registerExtendedAvailabilityCallback(mCameraManager,
+            &mCbs);
+    ASSERT_EQ(ret, ACAMERA_OK);
+
+    sleep(1);
+
+    // Should at least get onAvailable for each camera once
+    ASSERT_EQ(mAvailabilityListener.getAvailableCount(), mCameraIdList->numCameras);
+
+    // Expect no available callbacks for physical cameras
+    int availablePhysicalCamera = mAvailabilityListener.getPhysicalCameraAvailableCount();
+    ASSERT_EQ(availablePhysicalCamera, 0);
+
+    CameraServiceListener::StringPairSet unavailablePhysicalCameras;
+    CameraServiceListener::StringPairSet physicalCameraIdPairs;
+
+    unavailablePhysicalCameras = mAvailabilityListener.getUnavailablePhysicalCameras();
+    for (int i = 0; i < mCameraIdList->numCameras; i++) {
+        const char* cameraId = mCameraIdList->cameraIds[i];
+        ASSERT_NE(cameraId, nullptr);
+        ASSERT_TRUE(mAvailabilityListener.isAvailable(cameraId));
+
+        ACameraMetadata* chars = nullptr;
+        ret = ACameraManager_getCameraCharacteristics(mCameraManager, cameraId, &chars);
+        ASSERT_EQ(ret, ACAMERA_OK);
+        ASSERT_NE(chars, nullptr);
+
+        size_t physicalCameraCnt = 0;
+        const char *const* physicalCameraIds = nullptr;
+        if (!ACameraMetadata_isLogicalMultiCamera(
+                chars, &physicalCameraCnt, &physicalCameraIds)) {
+            ACameraMetadata_free(chars);
+            continue;
+        }
+        for (size_t j = 0; j < physicalCameraCnt; j++) {
+            physicalCameraIdPairs.emplace(cameraId, physicalCameraIds[j]);
+        }
+        ACameraMetadata_free(chars);
+    }
+    for (const auto& unavailIdPair : unavailablePhysicalCameras) {
+        bool validPair = false;
+        for (const auto& idPair : physicalCameraIdPairs) {
+            if (idPair.first == unavailIdPair.first && idPair.second == unavailIdPair.second) {
+                validPair = true;
+                break;
+            }
+        }
+        // Expect valid unavailable physical cameras
+        ASSERT_TRUE(validPair);
+    }
+
+    ret = ACameraManager_unregisterExtendedAvailabilityCallback(mCameraManager, &mCbs);
+    ASSERT_EQ(ret, ACAMERA_OK);
+}
+
+}  // namespace