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
gugelfrei
Emilian Peev 5 years ago
parent e8f70444fb
commit c6f2ab3c7b

@ -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){

@ -193,6 +193,20 @@ void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
}
}
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<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 @@ binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
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);

@ -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<CameraManagerGlobal> 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<Callback> 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<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

@ -278,6 +278,105 @@ camera_status_t ACameraManager_openCamera(
#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 */

@ -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;

@ -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
*/

Loading…
Cancel
Save