Nowości dotyczące usług

Nie tylko pojedyncze funkcje: gwarancja kombinacji funkcji w CameraX 1.5

6 min czytania
Tahsin Masrur
Inżynier oprogramowania

Nowoczesne aplikacje aparatu charakteryzują się zaawansowanymi, nakładającymi się na siebie funkcjami. Użytkownicy oczekują, że będą mogli nagrywać filmy w oszałamiającej jakości HDR, rejestrować płynny ruch z szybkością 60 kl./s i uzyskiwać płynny materiał dzięki stabilizacji podglądu – często jednocześnie.

Jako programiści wiemy, że rzeczywistość jest bardziej skomplikowana. Jak możesz zagwarantować, że dane urządzenie rzeczywiście obsługuje daną kombinację? Do tej pory włączanie wielu funkcji było często loterią. Możesz sprawdzić, czy poszczególne funkcje są obsługiwane, ale ich połączenie może prowadzić do nieokreślonego zachowania lub, co gorsza, do nieudanej sesji aparatu. Ta niepewność zmusza programistów do zachowawczości, co uniemożliwia użytkownikom korzystanie z najlepszych możliwych funkcji na urządzeniach, które je obsługują.

Na przykład bardzo niewiele urządzeń premium obsługuje jednocześnie HDR i wideo z szybkością 60 kl./s. W związku z tym większość aplikacji unika włączania obu tych funkcji jednocześnie, aby zapobiec pogorszeniu jakości obsługi na większości telefonów.

Aby rozwiązać ten problem, wprowadzamy grupę funkcji w CameraX – nowy interfejs API, który ma wyeliminować te domysły. Możesz teraz sprawdzić, czy dana kombinacja funkcji jest obsługiwana zanim skonfigurujesz aparat, lub po prostu określić priorytety w CameraX i pozwolić jej włączyć najlepiej obsługiwaną kombinację.

Dla osób, które dopiero zaczynają korzystać z CameraX

Zanim przejdziemy do nowego interfejsu Feature Group API, przypomnijmy, czym jest CameraX. CameraX to biblioteka obsługi Jetpack, która ułatwia tworzenie aplikacji aparatu. Zapewnia spójny i łatwy w użyciu interfejs API, który działa na większości urządzeń z Androidem i jest wstecznie zgodny z Androidem 6.0 (poziom interfejsu API 23). Jeśli dopiero zaczynasz korzystać z CameraX, zalecamy zapoznanie się z oficjalną dokumentacją i wypróbowanie codelabu.

Co możesz tworzyć za pomocą interfejsu Feature Group API

Nie musisz już polegać na kombinacjach funkcji i możesz z pewnością oferować najlepsze możliwe funkcje aparatu, takie jak jednoczesne nagrywanie w HDR i z szybkością 60 kl./s na odpowiednim sprzęcie (np. Pixel 10 Pro), a jednocześnie unikać błędów na urządzeniach, które nie obsługują tej kombinacji.

unnamed.png

Pixel 10 Pro umożliwia jednoczesne włączenie HDR i 60 kl./s

unnamed (1).png

Na starszym urządzeniu, na którym HDR i 60 kl./s nie mogą działać jednocześnie, włączony jest tylko HDR, a opcja 60 kl./s jest wyłączona.

Za pomocą interfejsu Feature Group API możesz:

  • Tworzyć inteligentniejsze, dynamiczne interfejsy: inteligentnie włączać i wyłączać ustawienia w interfejsie na podstawie obsługi sprzętu w czasie rzeczywistym. Jeśli na przykład użytkownik włączy HDR, możesz natychmiast wyszarzyć i wyłączyć opcję 60 kl./s, jeśli ta kombinacja nie jest obsługiwana na danym urządzeniu.
unsupported-features-disabled.gif
  • Zapewniać niezawodny tryb „Wysoka jakość”:  skonfiguruj aparat za pomocą listy preferowanych funkcji. CameraX automatycznie znajduje i włącza najlepiej obsługiwaną kombinację na danym urządzeniu, zapewniając doskonały efekt bez złożonej logiki specyficznej dla urządzenia.
  • Zapobiegać awariom sesji aparatu: dzięki wcześniejszemu sprawdzeniu obsługi zapobiegasz próbom skonfigurowania nieobsługiwanej kombinacji przez aparat, co eliminuje częste przyczyny awarii i zapewnia płynną obsługę.

Jak to działa: podstawowe komponenty

Nowy interfejs API opiera się na kluczowych dodatkach do SessionConfigCameraInfo.

  1. GroupableFeature: ten interfejs API wprowadza zestaw wstępnie zdefiniowanych funkcji, które można grupować, takich jak HDR_HLG10FPS_60, PREVIEW_STABILIZATIONIMAGE_ULTRA_HDR. Ze względu na ograniczenia obliczeniowe tylko określony zestaw funkcji można grupować z wysokim stopniem niezawodności, jaki zapewnia ten interfejs API. Aktywnie pracujemy nad rozszerzeniem tej listy i w przyszłych wersjach wprowadzimy obsługę większej liczby funkcji.
  2. Nowe parametry SessionConfig: ta klasa, która służy do rozpoczynania sesji aparatu, akceptuje teraz 2 nowe parametry:
    • requiredFeatureGroup: używaj tej opcji w przypadku funkcji, które muszą być obsługiwane, aby konfiguracja się powiodła – idealne rozwiązanie w przypadku funkcji, które użytkownik włącza bezpośrednio, np. przełączając przełącznik „HDR”. Aby zapewnić deterministyczne i spójne działanie, wywołanie bindToLifecycle zgłosi wyjątek IllegalArgumentException, jeśli żądana kombinacja nie jest obsługiwana, zamiast ignorować prośbę o dodanie funkcji. Aby wcześniej sprawdzić ten wynik, użyj interfejsu CameraInfo#isFeatureGroupSupported API (szczegóły poniżej).
    • preferredFeatureGroup: używaj tej opcji w przypadku funkcji, które są pożądane, ale opcjonalne, np. gdy chcesz wdrożyć domyślny tryb „Wysoka jakość”. Podajesz listę preferowanych funkcji uporządkowaną według priorytetów, a CameraX automatycznie włącza kombinację o najwyższym priorytecie, którą obsługuje urządzenie.
  3. CameraInfo#isFeatureGroupSupported(): jest to podstawowa metoda sprawdzania, czy grupa funkcji jest obsługiwana. Jest ona odpowiednia do udostępniania użytkownikom w interfejsie aplikacji tylko obsługiwanych opcji funkcji. Przekazujesz do niej SessionConfig, a ona zwraca wartość logiczną wskazującą, czy kombinacja jest obsługiwana. Jeśli zamierzasz powiązać SessionConfig z wymaganymi funkcjami, najpierw użyj tego interfejsu API, aby upewnić się, że jest on obsługiwany. 

Implementacja w praktyce

Zobaczmy, jak używać tych komponentów do tworzenia lepszych funkcji aparatu.

Scenariusz 1. Tryb „Wysoka jakość”

Jeśli chcesz domyślnie włączyć najlepsze możliwe funkcje, możesz podać listę priorytetów w preferredFeatureGroup. W tym przykładzie informujemy CameraX, aby priorytetowo traktowała HDR, następnie 60 kl./s, a na końcu stabilizację podglądu. CameraX zajmuje się złożonością sprawdzania wszystkich możliwych kombinacji i wybierania najlepszej, którą obsługuje urządzenie.

Jeśli na przykład urządzenie może obsługiwać HDR i 60 kl./s razem, ale nie ze stabilizacją podglądu, CameraX włączy pierwsze 2 funkcje i odrzuci trzecią. Dzięki temu możesz uzyskać najlepsze możliwe wrażenia bez pisania złożonych, specyficznych dla urządzenia sprawdzeń.

cameraProvider.bindToLifecycle(

    lifecycleOwner,

    cameraSelector,

    SessionConfig(

        useCases = listOf(preview, videoCapture),

        // The order of features in this list determines their priority. 

        // CameraX will enable the best-supported combination based on these

        // priorities: HDR_HLG10 > FPS_60 > Preview Stabilization.  

        preferredFeatureGroup =

           listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),

    ).apply {

        // (Optional) Get a callback with the enabled features

        // to update your UI. 

        setFeatureSelectionListener { selectedFeatures ->

            updateUiIndicators(selectedFeatures)

        }

    }

)

W przypadku tego fragmentu kodu CameraX będzie próbować włączyć kombinacje funkcji w tej kolejności priorytetów, wybierając pierwszą, którą urządzenie w pełni obsługuje:

  1. HDR + 60 kl./s + stabilizacja podglądu
  2. HDR + 60 kl./s
  3. HDR + stabilizacja podglądu
  4. HDR
  5. 60 kl./s + stabilizacja podglądu
  6. 60 kl./s
  7. Stabilizacja podglądu
  8. Żadna z powyższych funkcji

Scenariusz 2. Tworzenie reaktywnego interfejsu

Aby utworzyć interfejs, który reaguje na wybory użytkownika i uniemożliwia mu wybranie nieobsługiwanej kombinacji funkcji, możesz bezpośrednio sprawdzić obsługę. Poniższa funkcja sprawdza, które funkcje są niezgodne z bieżącymi wyborami użytkownika, co pozwala wyłączyć odpowiednie elementy interfejsu.

/**

 * Returns a list of features that are NOT supported in combination

 * with the currently selected features.

 */

fun getUnsupportedFeatures(

    currentFeatures: Set<GroupableFeature>

): Set<GroupableFeature> {

    val unsupportedFeatures = mutableSetOf<GroupableFeature>()

    val appFeatureOptions = setOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION)


    // Iterate over every available feature option in your app. 

    appFeatureOptions.forEach { featureOption ->

        // Skip features the user has already selected. 

        if (currentFeatures.contains(featureOption)) return@forEach


        // Check if adding this new feature is supported. 

        val isSupported = cameraInfo.isFeatureGroupSupported(

            SessionConfig(

                useCases = useCases,

                // Check the new feature on top of existing ones.

                requiredFeatureGroup = currentFeatures + featureOption

            )

        )


        if (!isSupported) {

            unsupportedFeatures.add(featureOption)

        }

    }


    return unsupportedFeatures

}

Następnie możesz połączyć tę logikę z ViewModel lub kontrolerem interfejsu, aby reagować na dane wejściowe użytkownika i ponownie powiązać aparat z konfiguracją, która na pewno będzie działać.

// Invoked when user turns some feature on/off.

fun onFeatureChange(currentFeatures: Set<GroupableFeature>) {

    // Identify features that are unsupported with the current selection.

    val unsupportedFeatures = getUnsupportedFeatures(currentFeatures)



    // Update app UI so that users can't enable them.

    updateDisabledFeatures(unsupportedFeatures)



    // Since the UI now only allows selecting supported feature combinations, 

    // `currentFeatures` is always valid. This allows setting

    // `requiredFeatureGroup` directly, without needing to re-check for

    // support or set a feature selection listener.  

    cameraProvider.bindToLifecycle(

        lifecycleOwner,

        cameraSelector,

        SessionConfig(

            useCases = listOf(preview, videoCapture),

            requiredFeatureGroup = currentFeatures,

        )

    )

}

Aby zobaczyć te koncepcje w działającej aplikacji, możesz zapoznać się z naszą wewnętrzną aplikacją testową. Zawiera ona pełną implementację zarówno scenariusza „najlepsze rozwiązanie”, jak i „reaktywny interfejs” omówionych powyżej.

Uwaga: jest to aplikacja testowa, a nie oficjalnie obsługiwany przykład. Chociaż jest to świetny punkt odniesienia dla interfejsu Feature Group API, nie został on dopracowany do użytku produkcyjnego.

Rozpocznij już dziś

Interfejs Feature Group API eliminuje niejasności związane z zaawansowanymi funkcjami aparatu. Dzięki deterministycznemu sposobowi sprawdzania obsługi funkcji możesz z pewnością tworzyć wydajniejsze i bardziej niezawodne aplikacje aparatu.

Interfejs API jest dostępny w wersji eksperymentalnej w CameraX 1.5, a w wersji 1.6 ma stać się w pełni stabilny. W przyszłości planujemy wprowadzić więcej obsługi i ulepszeń.

Więcej informacji znajdziesz w oficjalnej dokumentacji. Nie możemy się doczekać, aż zobaczysz, co stworzysz, i czekamy na Twoje opinie. Podziel się swoimi przemyśleniami i zgłoś wszelkie problemy za pomocą tych kanałów:

Autor:

Czytaj dalej