Używanie prognozowanego kontekstu do uzyskiwania dostępu do sprzętu okularów AI

Odpowiednie urządzenia XR
Te wskazówki pomogą Ci tworzyć aplikacje na te typy urządzeń XR.
Okulary AI

Gdy poprosisz o niezbędne uprawnienia i je uzyskasz, Twoja aplikacja będzie mieć dostęp do sprzętu okularów z AI. Kluczem do uzyskania dostępu do hardware okularów (zamiast hardware telefonu) jest użycie prognozowanego kontekstu.

Istnieją 2 podstawowe sposoby uzyskiwania prognozowanego kontekstu, w zależności od tego, gdzie jest wykonywany kod:

Jak uzyskać prognozowany kontekst, jeśli kod jest uruchamiany w aktywności związanej z okularami z AI

Jeśli kod aplikacji jest uruchamiany w ramach aktywności okularów z AI, własny kontekst aktywności jest już prognozowanym kontekstem. W takim przypadku połączenia wykonywane w ramach tej aktywności mogą już korzystać z hardware okularów.

Jak uzyskać prognozowany kontekst, jeśli kod jest uruchamiany w komponencie aplikacji na telefon

Jeśli część aplikacji poza aktywnością związaną z okularami z AI (np. aktywność na telefonie lub usługa) musi mieć dostęp do hardware okularów, musi wyraźnie uzyskać prognozowany kontekst. Aby to zrobić, użyj metody 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
    }
}

Sprawdź ważność

Po utworzeniu prognozowanego kontekstu monitoruj ProjectedContext.isProjectedDeviceConnected. Chociaż ta metoda zwraca wartość true, prognozowany kontekst pozostaje ważny dla połączonego urządzenia, a aktywność w aplikacji na telefonie lub usługa (np. CameraManager) może uzyskać dostęp do sprzętu okularów z AI.

Zwalnianie miejsca po odłączeniu

Przewidywany kontekst jest powiązany z cyklem życia połączonego urządzenia, więc jest usuwany po rozłączeniu urządzenia. Gdy urządzenie zostanie odłączone, ProjectedContext.isProjectedDeviceConnected zwróci wartość false. Aplikacja powinna nasłuchiwać tej zmiany i zwalniać miejsce zajmowane przez wszystkie usługi systemowe (np. CameraManager) lub zasoby, które utworzyła przy użyciu tego kontekstu.

Ponowna inicjalizacja po ponownym połączeniu

Gdy urządzenie z okularami AI ponownie się połączy, aplikacja może uzyskać kolejną instancję kontekstu projecji za pomocą createProjectedDeviceContext(), a następnie ponownie zainicjować dowolne usługi systemowe lub zasoby przy użyciu nowego kontekstu projecji.

Dostęp do dźwięku przez Bluetooth

Obecnie okulary z AI łączą się z telefonem jako standardowe urządzenie audio Bluetooth. Obsługiwane są zarówno profile zestawu słuchawkowego, jak i A2DP (Advanced Audio Distribution Profile). Dzięki temu każda aplikacja na Androida, która obsługuje wejście lub wyjście audio, może działać na okularach, nawet jeśli nie została specjalnie zaprojektowana do ich obsługi. W niektórych przypadkach używanie Bluetootha może być lepszym rozwiązaniem dla Twojej aplikacji niż uzyskiwanie dostępu do hardware okularów za pomocą prognozowanego kontekstu.

Podobnie jak w przypadku każdego standardowego urządzenia audio Bluetooth, uprawnienie do przyznania uprawnienia RECORD_AUDIO jest kontrolowane przez telefon, a nie przez okulary.

Robienie zdjęć aparatem okularów z AI

Aby zrobić zdjęcie aparatem okularów z AI, skonfiguruj i powiąż przypadek użycia ImageCapture CameraX z aparatem okularów, używając kontekstu odpowiedniego dla aplikacji:

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))
}

Najważniejsze informacje o kodzie

  • Pobiera instancję ProcessCameraProvider za pomocą prognozowanego kontekstu urządzenia.
  • W zakresie prognozowanego kontekstu główny aparat okularów z AI skierowany na zewnątrz jest mapowany na DEFAULT_BACK_CAMERA podczas wybierania aparatu.
  • Sprawdzanie przed powiązaniem wykorzystuje cameraProvider.hasCamera(cameraSelector), aby zanim przejdziesz dalej, było wiadomo, czy wybrany aparat jest dostępny na urządzeniu.
  • Używa Camera2 InteropCamera2CameraInfo do odczytywania podstawowej CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP, co może być przydatne w przypadku zaawansowanych kontroli obsługiwanych rozdzielczości.
  • Niestandardowy ResolutionSelector został opracowany z myślą o precyzyjnym kontrolowaniu rozdzielczości obrazu wyjściowego w przypadku ImageCapture.
  • Tworzy przypadek użycia ImageCapture skonfigurowany za pomocą niestandardowego ResolutionSelector.
  • Wiąże przypadek użycia ImageCapture z cyklem życia aktywności. Ta funkcja automatycznie zarządza otwieraniem i zamykaniem aparatu na podstawie stanu aktywności (np. zatrzymuje aparat, gdy aktywność jest wstrzymana).

Po skonfigurowaniu aparatu w okularach z AI możesz zrobić zdjęcie za pomocą klasy ImageCapture CameraX. Więcej informacji o używaniu takePicture() do robienia zdjęć znajdziesz w dokumentacji CameraX.

Nagrywanie filmów aparatem okularów z AI

Aby nagrać film zamiast zrobić zdjęcie za pomocą aparatu w okularach z AI, zastąp komponenty ImageCapture odpowiednimi komponentami VideoCapture i zmodyfikuj logikę wykonywania przechwytywania.

Główne zmiany polegają na zastosowaniu innego przypadku użycia, utworzeniu innego pliku wyjściowego i rozpoczęciu przechwytywania za pomocą odpowiedniej metody nagrywania wideo. Więcej informacji o interfejsie VideoCapture API i sposobie jego używania znajdziesz w dokumentacji CameraX dotyczącej nagrywania filmów.

W tabeli poniżej znajdziesz zalecaną rozdzielczość i liczbę klatek w zależności od zastosowania aplikacji:

Przypadek użycia Rozdzielczość Liczba klatek
Komunikacja wideo 1280 x 720 15 kl./s
Rozpoznawanie obrazów 640 x 480 10 kl./s
Strumieniowe przesyłanie filmów wygenerowanych przez AI 640 x 480 1 kl./s

Dostęp do sprzętu telefonu z poziomu aktywności na okularach z AI

Aktywność na okularach z AI może też uzyskać dostęp do hardware telefonu (np. aparatu lub mikrofonu) za pomocą createHostDeviceContext(context), aby zdobyć kontekst urządzenia hosta (telefonu):

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

Gdy w aplikacji hybrydowej (zawierającej zarówno funkcje mobilne, jak i funkcje na okulary z AI) uzyskujesz dostęp do sprzętu lub zasobów, które są specyficzne dla urządzenia hosta (telefonu), musisz wyraźnie wybrać odpowiedni kontekst, aby aplikacja mogła mieć dostęp do właściwego sprzętu: