Camera: Add NDK support for camera permission update callbacks
Camera NDK clients must receive notifications about
access permission changes.
Bug: 121379978
Test: Camera CTS
Change-Id: I66866ee3bbf7d45619995f036f19af50e812c236
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 8742d9c..23d01ef 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -105,6 +105,60 @@
}
EXPORT
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+ ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+ (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+ (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+ __FUNCTION__, callback,
+ callback->availabilityCallbacks.onCameraAvailable,
+ callback->availabilityCallbacks.onCameraUnavailable,
+ callback->onCameraAccessPrioritiesChanged);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ auto reservedEntriesCount = sizeof(callback->reserved) / sizeof(callback->reserved[0]);
+ for (size_t i = 0; i < reservedEntriesCount; i++) {
+ if (callback->reserved[i] != nullptr) {
+ ALOGE("%s: invalid argument! callback reserved entries must be set to NULL",
+ __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+ CameraManagerGlobal::getInstance().registerExtendedAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+ ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+ (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+ (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+ __FUNCTION__, callback,
+ callback->availabilityCallbacks.onCameraAvailable,
+ callback->availabilityCallbacks.onCameraUnavailable,
+ callback->onCameraAccessPrioritiesChanged);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ CameraManagerGlobal::getInstance().unregisterExtendedAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
camera_status_t ACameraManager_getCameraCharacteristics(
ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
ATRACE_CALL();
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 7d6ecac..9d40fd7 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -193,6 +193,20 @@
}
}
+void CameraManagerGlobal::registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.insert(cb);
+}
+
+void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
void CameraManagerGlobal::registerAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback) {
Mutex::Autolock _l(mLock);
@@ -289,12 +303,40 @@
(*cb)(context, cameraId.c_str());
break;
}
+ case kWhatSendSingleAccessCallback:
+ {
+ ACameraManager_AccessPrioritiesChangedCallback cb;
+ void* context;
+ AString cameraId;
+ 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;
+ }
+ (*cb)(context);
+ break;
+ }
default:
ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
break;
}
}
+binder::Status CameraManagerGlobal::CameraServiceListener::onCameraAccessPrioritiesChanged() {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ cm->onCameraAccessPrioritiesChanged();
+ } else {
+ ALOGE("Cannot deliver camera access priority callback. Global camera manager died");
+ }
+ return binder::Status::ok();
+}
+
binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
int32_t status, const String16& cameraId) {
sp<CameraManagerGlobal> cm = mCameraManager.promote();
@@ -306,6 +348,19 @@
return binder::Status::ok();
}
+void CameraManagerGlobal::onCameraAccessPrioritiesChanged() {
+ Mutex::Autolock _l(mLock);
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleAccessCallback, mHandler);
+ ACameraManager_AccessPrioritiesChangedCallback cbFp = cb.mAccessPriorityChanged;
+ if (cbFp != nullptr) {
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->post();
+ }
+ }
+}
+
void CameraManagerGlobal::onStatusChanged(
int32_t status, const String8& cameraId) {
Mutex::Autolock _l(mLock);
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index c3407f0..8c1da36 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -54,6 +54,11 @@
void unregisterAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback);
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+
/**
* Return camera IDs that support camera2
*/
@@ -86,10 +91,7 @@
return binder::Status::ok();
}
- // Access priority API not implemented yet
- virtual binder::Status onCameraAccessPrioritiesChanged() {
- return binder::Status::ok();
- }
+ virtual binder::Status onCameraAccessPrioritiesChanged();
private:
const wp<CameraManagerGlobal> mCameraManager;
@@ -101,11 +103,19 @@
explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
mAvailable(callback->onCameraAvailable),
mUnavailable(callback->onCameraUnavailable),
+ mAccessPriorityChanged(nullptr),
mContext(callback->context) {}
+ explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
+ mAvailable(callback->availabilityCallbacks.onCameraAvailable),
+ mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
+ mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+ mContext(callback->availabilityCallbacks.context) {}
+
bool operator == (const Callback& other) const {
return (mAvailable == other.mAvailable &&
mUnavailable == other.mUnavailable &&
+ mAccessPriorityChanged == other.mAccessPriorityChanged &&
mContext == other.mContext);
}
bool operator != (const Callback& other) const {
@@ -114,6 +124,9 @@
bool operator < (const Callback& other) const {
if (*this == other) return false;
if (mContext != other.mContext) return mContext < other.mContext;
+ if (mAccessPriorityChanged != other.mAccessPriorityChanged) {
+ return mAccessPriorityChanged < other.mAccessPriorityChanged;
+ }
if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
return mUnavailable < other.mUnavailable;
}
@@ -122,13 +135,15 @@
}
ACameraManager_AvailabilityCallback mAvailable;
ACameraManager_AvailabilityCallback mUnavailable;
+ ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
void* mContext;
};
std::set<Callback> mCallbacks;
// definition of handler and message
enum {
- kWhatSendSingleCallback
+ kWhatSendSingleCallback,
+ kWhatSendSingleAccessCallback,
};
static const char* kCameraIdKey;
static const char* kCallbackFpKey;
@@ -141,6 +156,7 @@
sp<CallbackHandler> mHandler;
sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+ void onCameraAccessPrioritiesChanged();
void onStatusChanged(int32_t status, const String8& cameraId);
void onStatusChangedLocked(int32_t status, const String8& cameraId);
// Utils for status
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index ea76738..1812901 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -278,6 +278,105 @@
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Definition of camera access permission change callback.
+ *
+ * <p>Notification that camera access priorities have changed and the camera may
+ * now be openable. An application that was previously denied camera access due to
+ * a higher-priority user already using the camera, or that was disconnected from an
+ * active camera session due to a higher-priority user trying to open the camera,
+ * should try to open the camera again if it still wants to use it. Note that
+ * multiple applications may receive this callback at the same time, and only one of
+ * them will succeed in opening the camera in practice, depending on exact access
+ * priority levels and timing. This method is useful in cases where multiple
+ * applications may be in the resumed state at the same time, and the user switches
+ * focus between them, or if the current camera-using application moves between
+ * full-screen and Picture-in-Picture (PiP) states. In such cases, the camera
+ * available/unavailable callbacks will not be invoked, but another application may
+ * now have higher priority for camera access than the current camera-using
+ * application.</p>
+
+ * @param context The optional application context provided by user in
+ * {@link ACameraManager_AvailabilityListener}.
+ */
+typedef void (*ACameraManager_AccessPrioritiesChangedCallback)(void* context);
+
+/**
+ * A listener for camera devices becoming available/unavailable to open or when
+ * the camera access permissions change.
+ *
+ * <p>Cameras become available when they are no longer in use, or when a new
+ * removable camera is connected. They become unavailable when some
+ * application or service starts using a camera, or when a removable camera
+ * is disconnected.</p>
+ *
+ * @see ACameraManager_registerExtendedAvailabilityCallback
+ */
+typedef struct ACameraManager_ExtendedAvailabilityListener {
+ ///
+ ACameraManager_AvailabilityCallbacks availabilityCallbacks;
+
+ /// Called when there is camera access permission change
+ ACameraManager_AccessPrioritiesChangedCallback onCameraAccessPrioritiesChanged;
+
+ /// Reserved for future use, please ensure that all entries are set to NULL
+ void *reserved[6];
+} ACameraManager_ExtendedAvailabilityCallbacks;
+
+/**
+ * Register camera extended availability callbacks.
+ *
+ * <p>onCameraUnavailable will be called whenever a camera device is opened by any camera API
+ * client. Other camera API clients may still be able to open such a camera device, evicting the
+ * existing client if they have higher priority than the existing client of a camera device.
+ * See {@link ACameraManager_openCamera} for more details.</p>
+ *
+ * <p>The callbacks will be called on a dedicated thread shared among all ACameraManager
+ * instances.</p>
+ *
+ * <p>Since this callback will be registered with the camera service, remember to unregister it
+ * once it is no longer needed; otherwise the callback will continue to receive events
+ * indefinitely and it may prevent other resources from being released. Specifically, the
+ * callbacks will be invoked independently of the general activity lifecycle and independently
+ * of the state of individual ACameraManager instances.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be registered.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if manager or callback is NULL, or
+ * {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ * or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ * {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+ ACameraManager* manager,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+/**
+ * Unregister camera extended availability callbacks.
+ *
+ * <p>Removing a callback that isn't registered has no effect.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be unregistered.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if callback,
+ * {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ * or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ * {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+ ACameraManager* manager,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAMERA_MANAGER_H */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 5a00022..b999368 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -22,6 +22,8 @@
ACameraManager_openCamera;
ACameraManager_registerAvailabilityCallback;
ACameraManager_unregisterAvailabilityCallback;
+ ACameraManager_registerExtendedAvailabilityCallback; # introduced=29
+ ACameraManager_unregisterExtendedAvailabilityCallback; # introduced=29
ACameraMetadata_copy;
ACameraMetadata_free;
ACameraMetadata_getAllTags;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 6b1365a..df69353 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -64,6 +64,11 @@
void unregisterAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback);
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+
/**
* Return camera IDs that support camera2
*/