diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp index 8742d9c97e..23d01efcac 100644 --- a/camera/ndk/NdkCameraManager.cpp +++ b/camera/ndk/NdkCameraManager.cpp @@ -104,6 +104,60 @@ camera_status_t ACameraManager_unregisterAvailabilityCallback( return ACAMERA_OK; } +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){ diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp index 7d6ecacbb4..9d40fd7144 100644 --- a/camera/ndk/impl/ACameraManager.cpp +++ b/camera/ndk/impl/ACameraManager.cpp @@ -193,6 +193,20 @@ void CameraManagerGlobal::DeathNotifier::binderDied(const wp&) } } +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 @@ void CameraManagerGlobal::CallbackHandler::onMessageReceived( (*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 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 cm = mCameraManager.promote(); @@ -306,6 +348,19 @@ binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged( return binder::Status::ok(); } +void CameraManagerGlobal::onCameraAccessPrioritiesChanged() { + Mutex::Autolock _l(mLock); + for (auto cb : mCallbacks) { + sp 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 c3407f0395..8c1da36418 100644 --- a/camera/ndk/impl/ACameraManager.h +++ b/camera/ndk/impl/ACameraManager.h @@ -54,6 +54,11 @@ class CameraManagerGlobal final : public RefBase { 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 @@ class CameraManagerGlobal final : public RefBase { 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 mCameraManager; @@ -101,11 +103,19 @@ class CameraManagerGlobal final : public RefBase { 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 @@ class CameraManagerGlobal final : public RefBase { 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 @@ class CameraManagerGlobal final : public RefBase { } ACameraManager_AvailabilityCallback mAvailable; ACameraManager_AvailabilityCallback mUnavailable; + ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged; void* mContext; }; std::set mCallbacks; // definition of handler and message enum { - kWhatSendSingleCallback + kWhatSendSingleCallback, + kWhatSendSingleAccessCallback, }; static const char* kCameraIdKey; static const char* kCallbackFpKey; @@ -141,6 +156,7 @@ class CameraManagerGlobal final : public RefBase { sp mHandler; sp 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 ea76738806..181290102d 100644 --- a/camera/ndk/include/camera/NdkCameraManager.h +++ b/camera/ndk/include/camera/NdkCameraManager.h @@ -278,6 +278,105 @@ camera_status_t ACameraManager_openCamera( #endif /* __ANDROID_API__ >= 24 */ +#if __ANDROID_API__ >= 29 + +/** + * Definition of camera access permission change callback. + * + *

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.

+ + * @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. + * + *

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.

+ * + * @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. + * + *

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.

+ * + *

The callbacks will be called on a dedicated thread shared among all ACameraManager + * instances.

+ * + *

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.

+ * + * @param manager the {@link ACameraManager} of interest. + * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be registered. + * + * @return
    + *
  • {@link ACAMERA_OK} if the method call succeeds.
  • + *
  • {@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.
+ */ +camera_status_t ACameraManager_registerExtendedAvailabilityCallback( + ACameraManager* manager, + const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29); + +/** + * Unregister camera extended availability callbacks. + * + *

Removing a callback that isn't registered has no effect.

+ * + * @param manager the {@link ACameraManager} of interest. + * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be unregistered. + * + * @return
    + *
  • {@link ACAMERA_OK} if the method call succeeds.
  • + *
  • {@link ACAMERA_ERROR_INVALID_PARAMETER} if callback, + * {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged} + * or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or + * {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.
+ */ +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 5a0002290a..b99936873c 100644 --- a/camera/ndk/libcamera2ndk.map.txt +++ b/camera/ndk/libcamera2ndk.map.txt @@ -22,6 +22,8 @@ LIBCAMERA2NDK { 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 6b1365a8c1..df6935336f 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraManager.h +++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h @@ -64,6 +64,11 @@ class CameraManagerGlobal final : public RefBase { void unregisterAvailabilityCallback( const ACameraManager_AvailabilityCallbacks *callback); + void registerExtendedAvailabilityCallback( + const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {} + void unregisterExtendedAvailabilityCallback( + const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {} + /** * Return camera IDs that support camera2 */