Obsługa wyświetlacza

Aktualizacje wprowadzone w tych obszarach specyficznych dla wyświetlacza są przedstawione poniżej:

Zmiana rozmiaru działań i wyświetlaczy

Aby wskazać, że aplikacja nie może obsługiwać tryb multi-okno lub zmiana rozmiaru, działalność użyć resizeableActivity=false atrybut. Typowe problemy napotykane przez aplikacje podczas zmiany rozmiaru aktywności obejmują:

  • Działanie może mieć inną konfigurację niż aplikacja lub inny składnik niewizualny. Częstym błędem jest odczytywanie metryk wyświetlania z kontekstu aplikacji. Zwracane wartości nie będą dostosowywane do metryk widocznego obszaru, w których wyświetlane jest działanie.
  • Aktywność może nie obsługiwać zmiany rozmiaru i awarii, wyświetlać zniekształcony interfejs użytkownika lub utracić stan z powodu ponownego uruchomienia bez zapisywania stanu instancji.
  • Aplikacja może próbować użyć bezwzględnych współrzędnych wejściowych (zamiast tych odnoszących się do pozycji okna), co może spowodować uszkodzenie danych wejściowych w wielu oknach.

W Androidzie 7 (lub wyższej), aplikacja może być zestaw resizeableActivity=false , aby zawsze działać w trybie pełnoekranowym. W takim przypadku platforma zapobiega przechodzeniu do podzielonego ekranu działań, których nie można zmienić. Jeśli użytkownik spróbuje wywołać działanie bez zmiany rozmiaru z programu uruchamiającego, gdy jest już w trybie podzielonego ekranu, platforma wyjdzie z trybu podzielonego ekranu i uruchomi działanie bez zmiany rozmiaru w trybie pełnoekranowym.

Aplikacje, które jawnie ustawić ten atrybut na false w manifeście nie musi być uruchomiony w trybie multi-okna, o ile nie zostanie zastosowany tryb zgodności:

  • Ta sama konfiguracja jest stosowana do procesu, który zawiera wszystkie działania i komponenty nieaktywne.
  • Zastosowana konfiguracja spełnia wymagania CDD dla wyświetlaczy zgodnych z aplikacjami.

W systemie Android 10 platforma nadal uniemożliwia przechodzenie działań bez zmiany rozmiaru do trybu podzielonego ekranu, ale można je tymczasowo skalować, jeśli działanie zadeklarowało stałą orientację lub współczynnik proporcji. Jeśli nie, aktywność zmienia się, aby wypełnić cały ekran, tak jak w Androidzie 9 i niższych.

Domyślna implementacja dotyczy następujących zasad:

Kiedy działalność uznana za niezgodną z multi-okno poprzez korzystanie z android:resizeableActivity atrybutu i gdy działalność ta spełnia jeden z warunków opisanych poniżej, a następnie, gdy konfiguracja ekran Applied musi zmienić, aktywność i proces są zapisywane z oryginalnej konfiguracji a użytkownik otrzymuje afordancję na ponowne uruchomienie procesu aplikacji, aby użyć zaktualizowanej konfiguracji ekranu.

  • Orientacja jest ustalona poprzez zastosowanie android:screenOrientation
  • Aplikacja ma domyślny maksymalny lub minimalny współczynnik proporcji przez kierowanie na poziom interfejsu API lub jawnie deklaruje współczynnik proporcji

Ten rysunek przedstawia aktywność, której rozmiar nie może być zmieniany, z zadeklarowanym współczynnikiem proporcji. Podczas składania urządzenia okno jest zmniejszane, aby dopasować się do obszaru, zachowując proporcje przy użyciu odpowiedniego letterboxa. Ponadto użytkownik otrzymuje opcję ponownego uruchomienia działania za każdym razem, gdy zmienia się obszar wyświetlania działania.

Podczas rozkładania urządzenia konfiguracja, rozmiar i proporcje działania nie zmieniają się, ale wyświetlana jest opcja ponownego uruchomienia działania.

Kiedy resizeableActivity nie jest ustawiony (lub jest ona ustawiona na true ), aplikacja w pełni popiera zmiany rozmiaru.

Realizacja

Działanie bez zmiany rozmiaru ze stałą orientacją lub współczynnikiem proporcji jest nazywane trybem zgodności rozmiaru (SCM) w kodzie. Warunkiem jest zdefiniowana w ActivityRecord#shouldUseSizeCompatMode() . Po uruchomieniu działania SCM konfiguracja związana z ekranem (taka jak rozmiar lub gęstość) jest ustalana w żądanej konfiguracji nadpisania, dzięki czemu działanie nie jest już zależne od bieżącej konfiguracji wyświetlania.

Jeśli aktywność SCM nie może wypełnić całego ekranu, jest wyrównana do góry i wyśrodkowana w poziomie. Granice aktywności są obliczane przez AppWindowToken#calculateCompatBoundsTransformation() .

Gdy aktywność SCM wykorzystuje inną konfigurację ekranu niż opakowanie (na przykład wyświetlacz jest zmieniany lub aktywność przeniesiony do innego wyświetlacz) ActivityRecord#inSizeCompatMode() jest prawdziwa i SizeCompatModeActivityController (w systemie ui) otrzymuje zwrotnego pokazania sposobu przycisk restartu.

Rozmiary wyświetlacza i proporcje

Android 10 zapewnia obsługę nowych proporcji, od wysokich proporcji długich i cienkich ekranów do proporcji 1:1. Aplikacje mogą definiować ApplicationInfo#maxAspectRatio i ApplicationInfo#minAspectRatio ekranu, które są w stanie obsłużyć.

proporcje aplikacji w Androidzie 10

Wskaźniki aplikacji figura 1. Przykład obsługiwane Android 10

Implementacje urządzenie może mieć wtórne wyświetlaczy o rozmiarach i rozdzielczościach mniejszych niż wymagane Androida 9 i dolnej części (co najmniej 2,5 cali wysokości i szerokości, co najmniej 320-DP o smallestScreenWidth ), lecz jedynie działania, które opcjonalnie w celu wspierania tych małych wyświetlaczy mogą być umieszczone tam.

Aplikacje mogą się włączyć, deklarując minimalny obsługiwany rozmiar, który jest mniejszy niż jeden równy docelowemu rozmiarowi ekranu. Użyj android:minHeight i android:minWidth atrybuty układu aktywność w AndroidManifest zrobić.

Zasady wyświetlania

Android 10 oddziela i porusza niektórych polityk wyświetlacza z domyślnej WindowManagerPolicy realizacji w PhoneWindowManager na zajęcia z ekranami, takie jak:

  • Stan wyświetlacza i obrót
  • Niektóre klawisze i śledzenie zdarzeń ruchu
  • Systemowy interfejs użytkownika i okna dekoracji

W Androidzie 9 (i mniejsze), w PhoneWindowManager klasa obsługiwanych wyświetlaczy polityki, państwa i ustawień, obrót, dekoracji okna śledzenia ramki, i wiele innych. Android 10 przemieszcza większość tego do DisplayPolicy klasie, z wyjątkiem śledzenia obrotów, który został przeniesiony do DisplayRotation .

Ustawienia okna wyświetlania

W systemie Android 10 konfigurowalne ustawienie okien dla poszczególnych ekranów zostało rozszerzone o:

  • Domyślny tryb wyświetlania okienek
  • Wartości overscan
  • Rotacja użytkownika i tryb rotacji
  • Wymuszony rozmiar, gęstość i tryb skalowania
  • Tryb usuwania treści (gdy wyświetlacz jest usunięty)
  • Wsparcie dla dekoracji systemu i IME

DisplayWindowSettings klasa zawiera ustawienia dla tych opcji. Oni utrzymywały się do płyty w /data partycji w display_settings.xml każdym razem, gdy ustawienie zostanie zmienione. Szczegółowe informacje można znaleźć DisplayWindowSettings.AtomicFileStorage i DisplayWindowSettings#writeSettings() . Producenci urządzeń mogą dostarczyć wartości domyślne w display_settings.xml do konfiguracji swojego urządzenia. Jednakże, ponieważ plik jest przechowywany w /data , dodatkowa logika może być konieczne, aby przywrócić plik, jeśli usunięte przez chusteczkę.

Domyślnie Android 10 wykorzystuje DisplayInfo#uniqueId jako identyfikator na wyświetlaczu podczas utrzymującego ustawienia. uniqueId powinny być wypełniane dla wszystkich wyświetlaczy. Ponadto jest stabilny dla wyświetlaczy fizycznych i sieciowych. Możliwe jest również do korzystania z portu fizycznego wyświetlaczu jako identyfikator, który można ustawić w DisplayWindowSettings#mIdentifier . Przy każdym zapisie zapisywane są wszystkie ustawienia, dzięki czemu można bezpiecznie zaktualizować klucz używany do wyświetlania wpisu w pamięci. Szczegółowe informacje można znaleźć statycznych wyświetlania identyfikatorów .

Ustawienia są zachowywane w /data katalog ze względów historycznych. Pierwotnie były używane do utrwalania ustawień użytkownika, takich jak obracanie wyświetlacza.

Statyczne identyfikatory wyświetlania

Android 9 (i starsze) nie zapewniał stabilnych identyfikatorów wyświetlaczy w ramach. Gdy wyświetlacz został dodany do systemu, Display#mDisplayId lub DisplayInfo#displayId została wygenerowana na tym wyświetlaczu inkrementacji licznika statycznego. Jeśli system dodał i usunął ten sam wyświetlacz, powstał inny identyfikator.

Jeśli urządzenie miało wiele wyświetlaczy dostępnych z rozruchu, wyświetlaczom można było przypisać różne identyfikatory, w zależności od czasu. Chociaż Android 9 (włącznie) zawarte DisplayInfo#uniqueId , nie zawierają wystarczających informacji, aby odróżnić wyświetlaczy ponieważ wyświetlacze zostały zidentyfikowane jako fizyczne bądź local:0 lub local:1 , do reprezentowania wbudowany i zewnętrzny wyświetlacz.

Android 10 zmiany DisplayInfo#uniqueId dodać identyfikator stabilne i odróżnić lokalnych sieci i wyświetla wirtualne.

Typ wyświetlacza Format
Lokalny
local:<stable-id>
Sieć
network:<mac-address>
Wirtualny
virtual:<package-name-and-name>

Oprócz aktualizacjach uniqueId , DisplayInfo.address zawiera DisplayAddress , identyfikator wyświetlacza, który jest stabilny podczas ponownego uruchamiania. W Androidzie 10, DisplayAddress obsługuje wyświetlacze fizycznych i sieciowych. DisplayAddress.Physical zawiera identyfikator stabilny wyświetlacza (tak samo jak w uniqueId ) i mogą być tworzone z DisplayAddress#fromPhysicalDisplayId() .

Android 10 zapewnia także wygodny sposób, aby uzyskać informacje o portach ( Physical#getPort() ). Ta metoda może być używana w ramach do statycznej identyfikacji wyświetlaczy. Na przykład, jest używany w DisplayWindowSettings ). DisplayAddress.Network zawiera adres MAC i mogą być tworzone z DisplayAddress#fromMacAddress() .

Te dodatki umożliwiają producentom urządzeń identyfikowanie wyświetlaczy w statycznych konfiguracjach z wieloma wyświetlaczami oraz konfigurowanie różnych ustawień i funkcji systemu przy użyciu statycznych identyfikatorów wyświetlaczy, takich jak porty dla wyświetlaczy fizycznych. Metody te są ukryte i są przeznaczone wyłącznie do wykorzystania w system_server .

Biorąc pod uwagę identyfikator wyświetlacza HWC (który może być nieprzezroczysty i nie zawsze stabilny), ta metoda zwraca (specyficzny dla platformy) 8-bitowy numer portu, który identyfikuje fizyczne złącze wyjściowe wyświetlacza, a także obiekt blob EDID wyświetlacza. SurfaceFlinger wyodrębnia informacje o producencie lub modelu z identyfikatora EDID w celu wygenerowania stabilnych 64-bitowych identyfikatorów wyświetlania wystawionych na działanie struktury. Jeśli ta metoda nie jest obsługiwany lub błędy out, SurfaceFlinger wraca do trybu legacy MD, gdzie DisplayInfo#address jest nieważna i DisplayInfo#uniqueId jest zakodowane, jak opisano powyżej.

Aby sprawdzić, czy ta funkcja jest obsługiwana, uruchom:

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

Korzystanie z więcej niż dwóch wyświetlaczy

W Androida 9 (i niższa), SurfaceFlinger i DisplayManagerService zakłada istnienie co najwyżej dwóch wyświetlaczy fizycznym z zakodowane identyfikatorów 0 i 1.

Począwszy od Androida 10, SurfaceFlinger może wykorzystywać interfejs API Hardware Composer (HWC) do generowania stabilnych identyfikatorów wyświetlania, co umożliwia zarządzanie dowolną liczbą fizycznych wyświetlaczy. Aby dowiedzieć się więcej, zobacz statycznych wyświetlania identyfikatorów .

Struktura może wyszukać IBinder token fizycznej wyświetlacza poprzez SurfaceControl#getPhysicalDisplayToken po uzyskaniu 64-bitowy identyfikator wyświetlania z SurfaceControl#getPhysicalDisplayIds lub z DisplayEventReceiver przypadku hotplug.

W Androida 10 (i dolnej), a główną wyświetlacz wewnętrzny TYPE_INTERNAL i wszystkie wskazania są oznaczone jako wtórne TYPE_EXTERNAL niezależnie od rodzaju połączenia. Dlatego dodatkowe wyświetlacze wewnętrzne są traktowane jako zewnętrzne. Jako obejście, kod specyficzny dla urządzenia można przyjąć założenia o DisplayAddress.Physical#getPort jeśli HWC jest znany i logika przydział portu jest przewidywalna.

To ograniczenie zostało usunięte w systemie Android 11 (i nowszym).

  • W systemie Android 11 pierwszy wyświetlacz zgłoszony podczas rozruchu jest wyświetlaczem podstawowym. Typ połączenia (wewnętrzne lub zewnętrzne) nie ma znaczenia. Prawdą jest jednak, że wyświetlacza głównego nie można odłączyć, co oznacza, że ​​w praktyce musi to być wyświetlacz wewnętrzny. Zwróć uwagę, że niektóre składane telefony mają wiele wewnętrznych wyświetlaczy.
  • Wyświetlacze wtórne są podzielone poprawnie Display.TYPE_INTERNAL lub Display.TYPE_EXTERNAL (dawniej znany jako Display.TYPE_BUILT_IN i Display.TYPE_HDMI , odpowiednio) w zależności od typu połączenia.

Realizacja

W Androida 9 i dolny, wyświetlacze są oznaczone 32-bitowymi identyfikatorów, gdzie 0 jest wyświetlacz wewnętrzny 1 jest wyświetlacz zewnętrzny [2, INT32_MAX] są hwc wirtualne wyświetlaczy, -1 oznacza nieprawidłowy wyświetlacza lub nie-hwc wirtualny wyświetlacz.

Począwszy od Androida 10, wyświetlacze podane są stabilne i trwałe identyfikatory, które pozwala SurfaceFlinger i DisplayManagerService śledzić więcej niż dwa monitory i wyświetlacze rozpoznać wcześniej widział. Jeżeli konfiguracja sprzętowa obsługuje IComposerClient.getDisplayIdentificationData dostarcza dane identyfikacyjne wyświetlacza SurfaceFlinger analizuje strukturę EDID i przydziela stałe 64-bitowy identyfikator ekranów wyświetlacza fizycznych i wirtualnych hwc. Identyfikatory są wyrażane przy użyciu typu opcji, gdzie wartość null reprezentuje nieprawidłowy ekran lub ekran wirtualny inny niż HWC. Bez obsługi HWC SurfaceFlinger powraca do starszego zachowania z co najwyżej dwoma fizycznymi wyświetlaczami.

Nacisk na wyświetlacz

Aby obsługiwać kilka źródeł danych wejściowych, które są kierowane na poszczególne wyświetlacze w tym samym czasie, system Android 10 można skonfigurować tak, aby obsługiwał wiele skoncentrowanych okien, maksymalnie jedno na wyświetlacz. Jest to przeznaczone tylko dla specjalnych typów urządzeń, gdy wielu użytkowników wchodzi w interakcję z tym samym urządzeniem w tym samym czasie i używa różnych metod wprowadzania lub urządzeń, takich jak Android Automotive.

Zaleca się, że ta funkcja nie jest włączona dla zwykłych urządzeń, w tym urządzeń multi-ekranowych lub tych stosowanych do komputerów stacjonarnych jak przeżyć. Wynika to głównie z obawy o bezpieczeństwo, która może spowodować, że użytkownicy będą się zastanawiać, które okno ma fokus.

Wyobraź sobie użytkownika, który wprowadza bezpieczne informacje w polu wprowadzania tekstu, na przykład logując się do aplikacji bankowej lub wprowadzając tekst zawierający poufne informacje. Złośliwa aplikacja może stworzyć wirtualny wyświetlacz pozaekranowy, za pomocą którego można wykonać czynność, również z polem wprowadzania tekstu. Uzasadnione i złośliwe działania są skoncentrowane i obie wyświetlają wskaźnik aktywnego wejścia (migający kursor).

Ponieważ jednak dane wprowadzane z klawiatury (sprzęt lub oprogramowanie) są wprowadzane tylko do najwyższej aktywności (aplikacji, która została ostatnio uruchomiona), przez utworzenie ukrytego wirtualnego wyświetlacza złośliwa aplikacja może przechwycić dane użytkownika, nawet przy użyciu klawiatury programowej na głównym wyświetlaczu urządzenia.

Zastosowanie com.android.internal.R.bool.config_perDisplayFocusEnabled do naciskiem zestaw per-wyświetlacza.

Zgodność

Problem: W Android 9 i niższy, co najwyżej jedno okno w systemie ma skupić na raz.

Rozwiązanie: W rzadkich przypadkach, gdy dwa okna z tego samego procesu byłyby skoncentrowane, system zapewnia skupić się tylko do okna, które jest wyższe w Z-order. To ograniczenie jest usuwane w przypadku aplikacji przeznaczonych dla systemu Android 10, w którym to momencie oczekuje się, że mogą obsługiwać jednocześnie wiele okien.

Realizacja

WindowManagerService#mPerDisplayFocusEnabled kontroluje dostępność tej funkcji. W ActivityManager , ActivityDisplay#getFocusedStack() jest obecnie wykorzystywana zamiast globalnego śledzenia w zmiennej. ActivityDisplay#getFocusedStack() określa ostrość na podstawie Z. Aby zamiast buforowanie wartości. Dzieje się tak, aby tylko jedno źródło, WindowManager, mogło śledzić kolejność działań Z.

ActivityStackSupervisor#getTopDisplayFocusedStack() przyjmuje podobne podejście do tych przypadków, gdy muszą zostać zidentyfikowane najwyższy skupiony stos w systemie. Stosy są przesuwane od góry do dołu w poszukiwaniu pierwszego kwalifikującego się stosu.

InputDispatcher może teraz mieć wiele ukierunkowanych okna (jeden na wyświetlaczu). Jeśli zdarzenie wejściowe jest specyficzne dla ekranu, jest wywoływane do aktywnego okna na odpowiednim ekranie. W przeciwnym razie jest wysyłany do aktywnego okna na aktywnym ekranie, czyli do ekranu, z którym użytkownik korzystał ostatnio.

Zobacz InputDispatcher::mFocusedWindowHandlesByDisplay i InputDispatcher::setFocusedDisplay() . Skoncentrowane aplikacje są również aktualizowane oddzielnie InputManagerService przez NativeInputManager::setFocusedApplication() .

W WindowManager , koncentruje okna są również śledzone oddzielnie. Zobacz DisplayContent#mCurrentFocus i DisplayContent#mFocusedApp i odpowiednich zastosowań. Powiązane metody śledzenia ostrości i aktualizowanie zostały przeniesione z WindowManagerService do DisplayContent .