Dopo aver richiesto e ottenuto le autorizzazioni necessarie, la tua app può accedere all'hardware degli occhiali AI. La chiave per accedere all'hardware degli occhiali (anziché a quello dello smartphone) è utilizzare un contesto proiettato.
Esistono due modi principali per ottenere un contesto proiettato, a seconda di dove viene eseguito il codice:
Ottieni un contesto proiettato se il codice viene eseguito in un'attività degli occhiali AI
Se il codice della tua app viene eseguito dall'attività degli occhiali AI, il suo contesto di attività è già un contesto proiettato. In questo scenario, le chiamate effettuate all'interno di questa attività possono già accedere all'hardware degli occhiali.
Ottenere un contesto proiettato per il codice in esecuzione in un componente dell'app per smartphone
Se una parte della tua app al di fuori dell'attività degli occhiali AI (ad esempio un'attività
di smartphone o un servizio) deve accedere all'hardware degli occhiali, deve ottenere
esplicitamente un contesto proiettato. Per farlo, utilizza il
metodo createProjectedDeviceContext():
@OptIn(ExperimentalProjectedApi::class) private fun getGlassesContext(context: Context): Context? { return try { // From a phone Activity or Service, get a context for the AI glasses. ProjectedContext.createProjectedDeviceContext(context) } catch (e: IllegalStateException) { Log.e(TAG, "Failed to create projected device context", e) null } }
Controllare la validità
Dopo aver creato il contesto proiettato, monitora
ProjectedContext.isProjectedDeviceConnected. Sebbene questo metodo restituisca
true, il contesto proiettato rimane valido per il dispositivo connesso e l'attività dell'app o il servizio per smartphone (ad esempio un CameraManager) può accedere all'hardware degli occhiali AI.
Liberare spazio alla disconnessione
Il contesto proiettato è legato al ciclo di vita del dispositivo connesso, quindi viene
eliminato quando il dispositivo si disconnette. Quando il dispositivo si disconnette,
ProjectedContext.isProjectedDeviceConnected restituisce false. La tua app deve rimanere in ascolto per questa modifica e liberare spazio da eventuali servizi di sistema (ad esempio un CameraManager) o risorse che ha creato utilizzando il contesto proiettato.
Reinizializza alla riconnessione
Quando il dispositivo occhiali AI si riconnette, la tua app può ottenere un'altra istanza di contesto proiettata utilizzando createProjectedDeviceContext() e poi reinizializzare qualsiasi servizio o risorsa di sistema utilizzando il nuovo contesto proiettato.
Accedere all'audio tramite Bluetooth
Al momento, gli occhiali AI si connettono allo smartphone come dispositivo audio Bluetooth standard. Sono supportati sia il profilo del visore sia il profilo A2DP (Advanced Audio Distribution Profile) . L'utilizzo di questo approccio consente a qualsiasi app per Android che supporta l'input o l'output audio di funzionare sugli occhiali, anche se non sono stati creati appositamente per supportare gli occhiali. In alcuni casi, l'utilizzo del Bluetooth potrebbe funzionare meglio per il caso d'uso della tua app come alternativa all'accesso all'hardware degli occhiali utilizzando un contesto proiettato.
Come per qualsiasi dispositivo audio Bluetooth standard, l'autorizzazione per concedere l'autorizzazione
RECORD_AUDIO è controllata dallo smartphone e non dagli occhiali.
Acquisire un'immagine con la fotocamera degli occhiali AI
Per acquisire un'immagine con la fotocamera degli occhiali AI, configura e associa lo scenario d'uso
ImageCapture di CameraX alla fotocamera degli occhiali utilizzando il contesto
corretto per la tua app:
private fun startCameraOnGlasses(activity: ComponentActivity) { // 1. Get the CameraProvider using the projected context. // When using the projected context, DEFAULT_BACK_CAMERA maps to the AI glasses' camera. val projectedContext = try { ProjectedContext.createProjectedDeviceContext(activity) } catch (e: IllegalStateException) { Log.e(TAG, "AI Glasses context could not be created", e) return } val cameraProviderFuture = ProcessCameraProvider.getInstance(projectedContext) cameraProviderFuture.addListener({ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // 2. Check for the presence of a camera. if (!cameraProvider.hasCamera(cameraSelector)) { Log.w(TAG, "The selected camera is not available.") return@addListener } // 3. Query supported streaming resolutions using Camera2 Interop. val cameraInfo = cameraProvider.getCameraInfo(cameraSelector) val camera2CameraInfo = Camera2CameraInfo.from(cameraInfo) val cameraCharacteristics = camera2CameraInfo.getCameraCharacteristic( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP ) // 4. Define the resolution strategy. val targetResolution = Size(1920, 1080) val resolutionStrategy = ResolutionStrategy( targetResolution, ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER ) val resolutionSelector = ResolutionSelector.Builder() .setResolutionStrategy(resolutionStrategy) .build() // 5. If you have other continuous use cases bound, such as Preview or ImageAnalysis, // you can use Camera2 Interop's CaptureRequestOptions to set the FPS val fpsRange = Range(30, 60) val captureRequestOptions = CaptureRequestOptions.Builder() .setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange) .build() // 6. Initialize the ImageCapture use case with options. val imageCapture = ImageCapture.Builder() // Optional: Configure resolution, format, etc. .setResolutionSelector(resolutionSelector) .build() try { // Unbind use cases before rebinding. cameraProvider.unbindAll() // Bind use cases to camera using the Activity as the LifecycleOwner. cameraProvider.bindToLifecycle( activity, cameraSelector, imageCapture ) } catch (exc: Exception) { Log.e(TAG, "Use case binding failed", exc) } }, ContextCompat.getMainExecutor(activity)) }
Punti chiave sul codice
- Ottiene un'istanza di
ProcessCameraProviderutilizzando il contesto del dispositivo proiettato. - Nell'ambito del contesto proiettato, la fotocamera principale degli occhiali AI, rivolta verso l'esterno, corrisponde a
DEFAULT_BACK_CAMERAquando selezioni una fotocamera. - Un controllo pre-binding utilizza
cameraProvider.hasCamera(cameraSelector)per verificare che la videocamera selezionata sia disponibile sul dispositivo prima di procedere. - Utilizza Camera2 Interop con
Camera2CameraInfoper leggere l'CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAPsottostante, che può essere utile per controlli avanzati sulle risoluzioni supportate. - Un
ResolutionSelectorpersonalizzato è creato per controllare con precisione la risoluzione dell'immagine di output perImageCapture. - Crea un caso d'uso
ImageCaptureconfigurato con unResolutionSelectorpersonalizzato. - Collega il caso d'uso
ImageCaptureal ciclo di vita dell'attività. In questo modo l'apertura e la chiusura della videocamera vengono gestite automaticamente in base allo stato dell'attività (ad esempio, la videocamera viene arrestata quando l'attività è in pausa).
Dopo aver configurato la fotocamera degli occhiali AI, puoi acquisire un'immagine con la
classe ImageCapture di CameraX. Consulta la documentazione di CameraX per scoprire come utilizzare takePicture() per acquisire un'immagine.
Acquisire un video con la videocamera degli occhiali AI
Per acquisire un video anziché un'immagine con la fotocamera degli occhiali AI, sostituisci i
componenti ImageCapture con i componenti VideoCapture corrispondenti
e modifica la logica di esecuzione dell'acquisizione.
Le modifiche principali riguardano l'utilizzo di un caso d'uso diverso, la creazione di un file di output diverso e l'avvio dell'acquisizione utilizzando il metodo di registrazione video appropriato.
Per saperne di più sull'API VideoCapture e su come utilizzarla, consulta la
documentazione relativa all'acquisizione video di CameraX.
La tabella seguente mostra la risoluzione e la frequenza fotogrammi consigliate a seconda del caso d'uso della tua app:
| Caso d'uso | Risoluzione | Frequenza fotogrammi |
|---|---|---|
| Videochiamata | 1280 x 720 | 15 f/s |
| Computer Vision | 640 x 480 | 10 f/s |
| Streaming video AI | 640 x 480 | 1 FPS |
Accedere all'hardware di uno smartphone da un'attività degli occhiali AI
Un'attività degli occhiali AI può accedere anche all'hardware dello smartphone (come la fotocamera
o il microfono) utilizzando createHostDeviceContext(context) per ottenere il contesto
del dispositivo host (smartphone):
@OptIn(ExperimentalProjectedApi::class) private fun getPhoneContext(activity: ComponentActivity): Context? { return try { // From an AI glasses Activity, get a context for the phone. ProjectedContext.createHostDeviceContext(activity) } catch (e: IllegalStateException) { Log.e(TAG, "Failed to create host device context", e) null } }
Quando accedi a hardware o risorse specifici del dispositivo host (smartphone) in un'app ibrida (un'app che contiene sia esperienze mobile che per occhiali AI), devi selezionare esplicitamente il contesto corretto per assicurarti che la tua app possa accedere all'hardware corretto:
- Utilizza il contesto
Activitydello smartphoneActivityoProjectedContext.createHostDeviceContext()per ottenere il contesto dello smartphone. - Non utilizzare
getApplicationContext()perché il contesto dell'applicazione può restituire in modo errato il contesto degli occhiali AI se un'attività degli occhiali è stato il componente avviato più di recente.