Urządzenia składane zapewniają wyjątkowe wrażenia podczas oglądania. Tryb wyświetlacza tylnego i tryb podwójnego ekranu umożliwiają tworzenie specjalnych funkcji wyświetlacza dla składanych urządzeń, takich jak podgląd selfie z tylnego aparatu czy jednoczesne wyświetlanie różnych treści na ekranie wewnętrznym i zewnętrznym.
Tryb tylnego wyświetlacza
Zazwyczaj, gdy urządzenie składane jest rozłożone, aktywny jest tylko ekran wewnętrzny. Tryb zewnętrznego wyświetlacza pozwala przenieść aktywność na zewnętrzny ekran składanego urządzenia, który zwykle jest odwrócony od użytkownika, gdy urządzenie jest rozłożone. wewnętrzny ekran automatycznie wyłącza się automatycznie.
Nowością jest wyświetlanie podglądu aparatu na ekranie zewnętrznym, dzięki czemu użytkownicy mogą robić selfie tylnym aparatem, który zwykle zapewnia znacznie lepsze wyniki podczas robienia zdjęć niż przedni aparat.
Aby włączyć tryb tylnego wyświetlacza, użytkownicy muszą odpowiedzieć w oknie, aby zezwolić aplikacji na: przełączać ekrany, na przykład:

Okno tworzy system, więc nie musisz nic programować. W zależności od stanu urządzenia wyświetlane są różne okna. na przykład system umożliwia użytkownikom otwieranie urządzenia, jeśli jest zamknięte. Tej opcji nie można dostosować i może się różnić w zależności od urządzenia różnych producentów OEM.
Tryb tylnego wyświetlacza możesz wypróbować w aplikacji aparatu Pixel Fold. Zobacz przykład w ramach ćwiczenia w Codelabs. Zoptymalizuj aplikację aparatu na urządzeniach składanych Jetpack WindowManager.
Tryb dwóch ekranów
Tryb 2 ekranów umożliwia wyświetlanie treści na obu wyświetlaczach urządzenia składanego jednocześnie. Tryb 2 ekranów jest dostępny na Pixelu Fold z Androidem 14 (poziom interfejsu API 34) lub wyższy.
Przykładem zastosowania jest tłumaczenie na 2 ekranach.

Włączanie trybów za pomocą kodu
Za pomocą Jetpacka możesz korzystać z trybu tylnego wyświetlacza i trybu podwójnego ekranu interfejsów API WindowManager, począwszy od biblioteki w wersji 1.2.0-beta03.
Dodaj zależność WindowManager do pliku build.gradle
modułu aplikacji:
Groovy
dependencies { implementation "androidx.window:window:1.2.0-beta03" }
Kotlin
dependencies { implementation("androidx.window:window:1.2.0-beta03") }
Punkt wejścia to WindowAreaController
, który zawiera informacje i zachowanie związane z przenoszeniem okien między wyświetlaczami lub obszarami wyświetlacza na urządzeniu. WindowAreaController
umożliwia wysyłanie zapytań dotyczących listy
dostępnych obiektów WindowAreaInfo
.
Użyj WindowAreaInfo
, aby uzyskać dostęp do WindowAreaSession
– interfejsu
reprezentuje funkcję obszaru aktywnych okien. Aby określić dostępność konkretnego WindowAreaCapability
, użyj elementu WindowAreaSession
.
Każda z nich jest powiązana z określonym WindowAreaCapability.Operation
.
W wersjach 1.2.0-beta03 Jetpack WindowManager obsługuje dwa rodzaje operacji:
WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA
, czyli służy do uruchamiania trybu dwóch ekranówWindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
, który służy do włączania trybu tylnego wyświetlacza
Oto przykład deklaracji zmiennych dla trybu tylnego wyświetlacza tryb dwóch ekranów w głównej aktywności w aplikacji:
Kotlin
private lateinit var windowAreaController: WindowAreaController private lateinit var displayExecutor: Executor private var windowAreaSession: WindowAreaSession? = null private var windowAreaInfo: WindowAreaInfo? = null private var capabilityStatus: WindowAreaCapability.Status = WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED private val dualScreenOperation = WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA private val rearDisplayOperation = WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
Java
private WindowAreaControllerCallbackAdapter windowAreaController = null; private Executor displayExecutor = null; private WindowAreaSessionPresenter windowAreaSession = null; private WindowAreaInfo windowAreaInfo = null; private WindowAreaCapability.Status capabilityStatus = WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED; private WindowAreaCapability.Operation dualScreenOperation = WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA; private WindowAreaCapability.Operation rearDisplayOperation = WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA;
Aby zainicjować zmienne w metodzie onCreate()
aktywności:
Kotlin
displayExecutor = ContextCompat.getMainExecutor(this) windowAreaController = WindowAreaController.getOrCreate() lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { windowAreaController.windowAreaInfos .map { info -> info.firstOrNull { it.type == WindowAreaInfo.Type.TYPE_REAR_FACING } } .onEach { info -> windowAreaInfo = info } .map { it?.getCapability(operation)?.status ?: WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED } .distinctUntilChanged() .collect { capabilityStatus = it } } }
Java
displayExecutor = ContextCompat.getMainExecutor(this); windowAreaController = new WindowAreaControllerCallbackAdapter(WindowAreaController.getOrCreate()); windowAreaController.addWindowAreaInfoListListener(displayExecutor, this); windowAreaController.addWindowAreaInfoListListener(displayExecutor, windowAreaInfos -> { for(WindowAreaInfo newInfo : windowAreaInfos){ if(newInfo.getType().equals(WindowAreaInfo.Type.TYPE_REAR_FACING)){ windowAreaInfo = newInfo; capabilityStatus = newInfo.getCapability(presentOperation).getStatus(); break; } } });
Przed rozpoczęciem operacji sprawdź dostępność określonych funkcje:
Kotlin
when (capabilityStatus) { WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED -> { // The selected display mode is not supported on this device. } WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNAVAILABLE -> { // The selected display mode is not available. } WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE -> { // The selected display mode is available and can be enabled. } WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE -> { // The selected display mode is already active. } else -> { // The selected display mode status is unknown. } }
Java
if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED)) { // The selected display mode is not supported on this device. } else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNAVAILABLE)) { // The selected display mode is not available. } else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE)) { // The selected display mode is available and can be enabled. } else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE)) { // The selected display mode is already active. } else { // The selected display mode status is unknown. }
Tryb dwóch ekranów
Poniższy przykład zamyka sesję, jeśli funkcja jest już aktywna.
w przeciwnym razie wywołuje funkcję presentContentOnWindowArea()
:
Kotlin
fun toggleDualScreenMode() { if (windowAreaSession != null) { windowAreaSession?.close() } else { windowAreaInfo?.token?.let { token -> windowAreaController.presentContentOnWindowArea( token = token, activity = this, executor = displayExecutor, windowAreaPresentationSessionCallback = this ) } } }
Java
private void toggleDualScreenMode() { if(windowAreaSession != null) { windowAreaSession.close(); } else { Binder token = windowAreaInfo.getToken(); windowAreaController.presentContentOnWindowArea( token, this, displayExecutor, this); } }
Zwróć uwagę, że głównym elementem aktywności aplikacji
WindowAreaPresentationSessionCallback
.
Interfejs API korzysta z metody listenera: gdy wysyłasz żądanie wyświetlenia treści na drugim wyświetlaczu składanego urządzenia, inicjujesz sesję, która jest zwracana za pomocą metody onSessionStarted()
listenera. Po zamknięciu sesji otrzymasz potwierdzenie w ramach metody onSessionEnded()
.
Aby utworzyć detektor, zaimplementuj WindowAreaPresentationSessionCallback
interfejs:
Kotlin
class MainActivity : AppCompatActivity(), windowAreaPresentationSessionCallback
Java
public class MainActivity extends AppCompatActivity implements WindowAreaPresentationSessionCallback
Listener musi zaimplementować metody onSessionStarted()
, onSessionEnded(),
i onContainerVisibilityChanged()
. Metody wywołania zwrotnego informują o stanie sesji i umożliwiają odpowiednie zaktualizowanie aplikacji.
Wywołanie zwrotne onSessionStarted()
otrzymuje WindowAreaSessionPresenter
jako
argument. Argumentem jest kontener umożliwiający dostęp do obszaru okna.
i pokazywać treści. System może automatycznie zamknąć prezentację
gdy użytkownik opuści główne okno aplikacji. Prezentacja może też
zostało zamknięte, dzwoniąc pod numer WindowAreaSessionPresenter#close()
.
W przypadku innych wywołań zwrotnych na potrzeby uproszczenia sprawdź w ciele funkcji, czy nie ma błędów, i zapisz stan:
Kotlin
override fun onSessionStarted(session: WindowAreaSessionPresenter) { windowAreaSession = session val view = TextView(session.context) view.text = "Hello world!" session.setContentView(view) } override fun onSessionEnded(t: Throwable?) { if(t != null) { Log.e(logTag, "Something was broken: ${t.message}") } } override fun onContainerVisibilityChanged(isVisible: Boolean) { Log.d(logTag, "onContainerVisibilityChanged. isVisible = $isVisible") }
Java
@Override public void onSessionStarted(@NonNull WindowAreaSessionPresenter session) { windowAreaSession = session; TextView view = new TextView(session.getContext()); view.setText("Hello world, from the other screen!"); session.setContentView(view); } @Override public void onSessionEnded(@Nullable Throwable t) { if(t != null) { Log.e(logTag, "Something was broken: ${t.message}"); } } @Override public void onContainerVisibilityChanged(boolean isVisible) { Log.d(logTag, "onContainerVisibilityChanged. isVisible = " + isVisible); }
Aby zachować spójność w całym ekosystemie, skorzystaj z oficjalnego Dual Screen , aby wskazać użytkownikom, jak włączyć lub wyłączyć tryb dwóch ekranów.
Praktyczny przykład znajdziesz na stronie DualScreenActivity.kt.
Tryb wyświetlania tylnego wyświetlacza
Podobnie jak w przypadku trybu dwóch ekranów, poniżej znajduje się przykład
Funkcja toggleRearDisplayMode()
zamyka sesję, jeśli może
już aktywny lub w inny sposób wywołuje metodę transferActivityToWindowArea()
funkcja:
Kotlin
fun toggleRearDisplayMode() { if(capabilityStatus == WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE) { if(windowAreaSession == null) { windowAreaSession = windowAreaInfo?.getActiveSession( operation ) } windowAreaSession?.close() } else { windowAreaInfo?.token?.let { token -> windowAreaController.transferActivityToWindowArea( token = token, activity = this, executor = displayExecutor, windowAreaSessionCallback = this ) } } }
Java
void toggleDualScreenMode() { if(capabilityStatus == WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE) { if(windowAreaSession == null) { windowAreaSession = windowAreaInfo.getActiveSession( operation ) } windowAreaSession.close() } else { Binder token = windowAreaInfo.getToken(); windowAreaController.transferActivityToWindowArea(token, this, displayExecutor, this); } }
W tym przypadku wyświetlana aktywność jest używana jako WindowAreaSessionCallback
, co jest prostsze do wdrożenia, ponieważ wywołanie zwrotne nie otrzymuje obiektu presenter, który umożliwia wyświetlanie treści w obszarze okna, ale zamiast tego przenosi całą aktywność do innego obszaru:
Kotlin
override fun onSessionStarted() { Log.d(logTag, "onSessionStarted") } override fun onSessionEnded(t: Throwable?) { if(t != null) { Log.e(logTag, "Something was broken: ${t.message}") } }
Java
@Override public void onSessionStarted(){ Log.d(logTag, "onSessionStarted"); } @Override public void onSessionEnded(@Nullable Throwable t) { if(t != null) { Log.e(logTag, "Something was broken: ${t.message}"); } }
Aby zachować spójność w całym ekosystemie, korzystaj z oficjalnego tylnego aparatu , aby wskazać użytkownikom sposób włączania i wyłączania trybu tylnego wyświetlacza.
Dodatkowe materiały
- Zoptymalizuj aplikację aparatu na urządzeniach składanych dzięki Jetpack WindowManager ćwiczenie w Codelabs
- Podsumowanie pakietu
androidx.window.area
- Przykładowy kod Jetpack WindowManager: