Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QtCameraAvailabilityListener.java
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4package org.qtproject.qt.android.multimedia;
5
6import android.app.Activity;
7import android.hardware.camera2.CameraManager;
8import android.os.Handler;
9import android.os.Looper;
10import android.util.Log;
11
12import org.qtproject.qt.android.UsedFromNativeCode;
13
14import java.util.concurrent.CountDownLatch;
15
16// This class implements the camera-device availability callbacks for Android CameraManager.
17// This class should only be used with QAndroidVideoDevices.
18// In the future it might make sense to a central QtVideoDeviceManager that everything references,
19// and to build this class' functionality into that.
20class QtCameraAvailabilityListener extends CameraManager.AvailabilityCallback {
21
22 static final String LOG_TAG = "QtCameraAvailabilityListener";
23
24 CameraManager mCameraManager = null;
25 // Holds the pointer to the QAndroidVideoDevices instance.
26 // Should only ever be accessed from mAvailabilityCallbackHandler thread.
27 long mVideoDevicesNativePtr = 0;
28
29 Handler mAvailabilityCallbackHandler = null;
30
31 // Called from any native C++ thread.
32 @UsedFromNativeCode
33 QtCameraAvailabilityListener(Activity activity, long videoDevicesNativePtr) {
34 mCameraManager = (CameraManager)activity.getSystemService(Activity.CAMERA_SERVICE);
35 mVideoDevicesNativePtr = videoDevicesNativePtr;
36
37 // We use the Android main UI thread for receiving callbacks.
38 mAvailabilityCallbackHandler = new Handler(activity.getMainLooper());
39
40 // TODO: This will call C++ updateNativeVideoDevices() for each currently available
41 // camera when registered, possibly leading to us enumerating video-devices unncessarily
42 // often, and also signalling QMediaDevices::videoInputsChanged more than necessary.
43 // This should generally not be a problem assuming the multimedia backend is initialized
44 // before user-code.
45 //
46 // A future solution could be to post a job on the handler and wait for it, or
47 // to dynamically add/remove devices from an internal list which is then returned in
48 // QAndroidVideoDevices::findVideoInputs()
49 mCameraManager.registerAvailabilityCallback(this, mAvailabilityCallbackHandler);
50 }
51
52 // Called by QAndroidVideoDevices destructor.
53 // Posts a blocking job to background thread to clear the
54 // reference to QAndroidVideoDevices, then returns after
55 // reference is cleared.
56 @UsedFromNativeCode
57 void cleanup() {
58 assert(!mAvailabilityCallbackHandler.getLooper().isCurrentThread());
59
60 // Perform cleanup on the same thread that we receive callbacks, then wait for cleanup job
61 // to finish. No need for locks.
62 final CountDownLatch latch = new CountDownLatch(1);
63 final boolean postSuccess = mAvailabilityCallbackHandler.post(() -> {
64 mCameraManager.unregisterAvailabilityCallback(this);
65 assert(mVideoDevicesNativePtr != 0);
66 mVideoDevicesNativePtr = 0;
67 latch.countDown(); // Signal that the task is done
68 });
69
70 if (!postSuccess) {
71 Log.w(
72 LOG_TAG,
73 "Unable to post cleanup job to corresponding thread during " +
74 "QAndroidVideoDevices cleanup.");
75 return;
76 }
77
78 try {
79 latch.await();
80 } catch (Exception e) {
81 Log.w(
82 LOG_TAG,
83 "Unable to wait for cleanup job to finish on corresponding thread during" +
84 "QAndroidVideoDevices cleanup.");
85 }
86
87 // After waiting, QAndroidVideoDevices can now be safely destroyed.
88 }
89
90 native void onCameraAvailableNative(long videoDevicesNativePtr);
91
92 // Will be called once for each connected camera device when availability-listener
93 // is attached to the Android CameraManager.
95 public void onCameraAvailable(String cameraId) {
96 assert(mAvailabilityCallbackHandler.getLooper().isCurrentThread());
97 assert(mVideoDevicesNativePtr != 0);
98 onCameraAvailableNative(mVideoDevicesNativePtr);
99 }
100
101 native void onCameraUnavailableNative(long videoDevicesNativePtr);
102
103 @Override
104 public void onCameraUnavailable(String cameraId) {
105 assert(mAvailabilityCallbackHandler.getLooper().isCurrentThread());
106 assert(mVideoDevicesNativePtr != 0);
107 onCameraUnavailableNative(mVideoDevicesNativePtr);
108 }
109
110 @Override
111 public void onCameraAccessPrioritiesChanged() {
112 // TODO: In the future we should handle camera priorities, such as when the camera-device
113 // is connected but is in use by another application, making the current application unable
114 // to use it until the device is released by the other application.
115 }
116}
Q_CORE_EXPORT QtJniTypes::Activity activity()
#define assert
@ Handler
void cleanup()