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:
Ottenere un contesto proiettato se il codice viene eseguito in un'attività degli occhiali AI
Se il codice della tua app viene eseguito dall'interno dell'attività degli occhiali AI, il contesto dell'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à dello smartphone o un servizio) deve accedere all'hardware degli occhiali, deve ottenere esplicitamente un contesto proiettato. Per farlo, utilizza il
createProjectedDeviceContext() metodo:
@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 } }
Verificare la validità
Inserisci la chiamata createProjectedDeviceContext all'interno di
ProjectedContext.isProjectedDeviceConnected. Mentre questo metodo restituisce true, il contesto proiettato rimane valido per il dispositivo connesso e l'attività o il servizio dell'app per smartphone (ad esempio un CameraManager) può accedere all'hardware degli occhiali AI.
Eseguire la pulizia in caso di 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 ed eseguire la pulizia di eventuali servizi di sistema (ad esempio un CameraManager) o risorse create dall'app utilizzando il contesto proiettato.
Reinizializzare in caso di riconnessione
Quando il dispositivo degli occhiali AI si riconnette, la tua app può ottenere un'altra istanza di contesto proiettato
utilizzando createProjectedDeviceContext() e poi
reinicializzare eventuali servizi o risorse di sistema utilizzando il nuovo contesto proiettato.
Accedere all'audio tramite Bluetooth
Al momento, gli occhiali AI si connettono allo smartphone come un dispositivo audio Bluetooth standard. Sono supportati sia il profilo auricolare sia il profilo A2DP (Advanced Audio Distribution Profile) profiles. Questo approccio consente a qualsiasi app per Android che supporta l'input o l'output audio di funzionare sugli occhiali, anche se non è stata creata appositamente per supportarli. In alcuni casi, l'utilizzo del Bluetooth potrebbe essere più adatto al caso d'uso della tua app come alternativa all'accesso all'hardware degli occhiali tramite un contesto proiettato.
Come per qualsiasi dispositivo audio Bluetooth standard, l'autorizzazione a concedere la
RECORD_AUDIO autorizzazione è 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 il caso d'uso
ImageCapture 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, viene mappata su
DEFAULT_BACK_CAMERAquando si seleziona una fotocamera. - Un controllo di pre-associazione utilizza
cameraProvider.hasCamera(cameraSelector)per verificare che la fotocamera selezionata sia disponibile sul dispositivo prima di procedere. - Utilizza Camera2 Interop con
Camera2CameraInfoper leggere il sottostanteCameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP, che può essere utile per controlli avanzati sulle risoluzioni supportate. - Viene creato un
ResolutionSelectorpersonalizzato per controllare con precisione la risoluzione dell'immagine di output perImageCapture. - Crea un caso d'uso
ImageCaptureconfigurato con unResolutionSelectorpersonalizzato. - Associa il caso d'uso
ImageCaptureal ciclo di vita dell'attività. In questo modo, l'apertura e la chiusura della fotocamera vengono gestite automaticamente in base allo stato dell'attività (ad esempio, la fotocamera 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 fotocamera degli occhiali AI
Per acquisire un video anziché un'immagine con la fotocamera degli occhiali AI, sostituisci i
ImageCapture componenti 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 ulteriori informazioni sull'API VideoCapture e su come utilizzarla, consulta la
documentazione di acquisizione video di CameraX.
La tabella seguente mostra la risoluzione e la frequenza fotogrammi consigliate a seconda del caso d'uso dell'app:
| Caso d'uso | Risoluzione | Frequenza fotogrammi |
|---|---|---|
| Comunicazione video | 1280 x 720 | 15 FPS |
| Visione artificiale | 640 x 480 | 10 FPS |
| 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ò anche accedere all'hardware dello smartphone (ad esempio 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 all'hardware o alle risorse specifici del dispositivo host (smartphone) in un'app ibrida (un'app che contiene sia esperienze per dispositivi mobili sia per occhiali AI), devi selezionare esplicitamente il contesto corretto per assicurarti che la tua app possa accedere all'hardware corretto:
- Utilizza il
Activitycontesto diActivitydello smartphone oProjectedContext.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 è il componente avviato più di recente.