Składane urządzenia zapewniają wyjątkowe wrażenia podczas oglądania. Tryb tylnego wyświetlacza i tryb Dual Screen umożliwiają wprowadzenie specjalnych funkcji wyświetlacza dla urządzeń składanych, takich jak podgląd selfie z tylnego aparatu oraz jednoczesne, ale różne wyświetlacze na ekranach wewnętrznym i zewnętrznym.
Tryb tylnego wyświetlacza
Zazwyczaj po rozłożeniu urządzenia składanego aktywna jest tylko część ekranu wewnętrznego. Tryb tylnego wyświetlacza pozwala przenieść aktywność na zewnętrzny ekran składanego urządzenia, które jest zwykle odwrócone od użytkownika, gdy jest rozłożone. Wyświetlacz wewnętrzny wyłącza się automatycznie.
Ta nowatorska aplikacja to wyświetlanie podglądu aparatu na ekranie zewnętrznym, aby użytkownicy mogli robić selfie tylnym aparatem, co zwykle umożliwia znacznie lepsze wykonywanie zdjęć.
Aby włączyć tryb tylnego wyświetlacza, użytkownicy muszą odpowiedzieć na okno pozwalające aplikacji na przełączanie ekranów. Na przykład:
To system tworzy okno dialogowe, więc nie musisz niczego programować. Okna są różne w zależności od stanu urządzenia, np. gdy jest ono zamknięte, system informuje użytkowników, że mają otworzyć urządzenie. Nie możesz dostosować tego okna, ale może się ono różnić w zależności od urządzenia danego producenta OEM.
Tryb tylnego wyświetlacza możesz wypróbować w aplikacji aparatu Pixel Fold. Zobacz przykładową implementację w ćwiczeniach z programowania Rozkładanie funkcji aparatu.
Tryb Dual Screen
Tryb Dual Screen umożliwia jednoczesne wyświetlanie treści na obu ekranach urządzenia składanego. Tryb podwójnego ekranu jest dostępny na urządzeniu Pixel Fold z Androidem 14 (poziom interfejsu API 34) lub nowszym.
Przykładem może być tłumacz na dwa ekrany.
Automatyczne włączanie trybów
Tryb tylnego wyświetlacza i tryb podwójnego ekranu możesz uzyskać za pomocą interfejsów API Jetpack WindowManager, począwszy od biblioteki w wersji 1.2.0-beta03.
Dodaj zależność WindowManager do pliku build.gradle
modułu aplikacji:
Odlotowy
dependencies { implementation "androidx.window:window:1.2.0-beta03" }
Kotlin
dependencies { implementation("androidx.window:window:1.2.0-beta03") }
Punktem wejścia jest WindowAreaController
, który udostępnia informacje i zachowania związane z przesuwaniem okien między wyświetlaczami i między obszarami wyświetlania na urządzeniu.
WindowAreaController
umożliwia wysyłanie zapytań o listę dostępnych obiektów WindowAreaInfo
.
Użyj WindowAreaInfo
, aby uzyskać dostęp do WindowAreaSession
, czyli interfejsu reprezentującego aktywną funkcję obszaru okna.
Użyj metody WindowAreaSession
, aby określić dostępność określonego typu WindowAreaCapability
.
Każda możliwość jest powiązana z konkretnym elementem WindowAreaCapability.Operation
.
W wersji 1.2.0-beta03 Jetpack WindowManager obsługuje dwa rodzaje operacji:
WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA
– służy do uruchamiania trybu podwójnego ekranu.WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
, które włącza tryb tylnego wyświetlacza;
Oto przykład deklaracji zmiennych dla trybu tylnego wyświetlacza i trybu dwóch ekranów w głównej aktywności 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ść danej funkcji:
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 currently available to be enabled. } WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE -> { // The selected display mode is currently available to 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 currently available to be enabled. } else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE)) { // The selected display mode is currently available to 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 Dual Screen
W tym przykładzie zamykamy sesję, jeśli możliwość jest już aktywna lub w inny sposób 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łówna aktywność w aplikacji jest używana jako WindowAreaPresentationSessionCallback
.
Interfejs API wykorzystuje metodę nasłuchiwania: gdy wysyłasz żądanie udostępnienia treści na inny wyświetlacz urządzenia składanego, inicjujesz sesję zwracaną przez metodę onSessionStarted()
detektora.
Gdy zamkniesz sesję, otrzymasz potwierdzenie w metodzie onSessionEnded()
.
Aby utworzyć detektor, zaimplementuj interfejs WindowAreaPresentationSessionCallback
:
Kotlin
class MainActivity : AppCompatActivity(), windowAreaPresentationSessionCallback
Java
public class MainActivity extends AppCompatActivity implements WindowAreaPresentationSessionCallback
Detektor musi wdrożyć metody onSessionStarted()
, onSessionEnded(),
i onContainerVisibilityChanged()
.
Metody wywołania zwrotnego powiadamiają o stanie sesji i pozwalają odpowiednio zaktualizować aplikację.
Wywołanie onSessionStarted()
odbiera argument WindowAreaSessionPresenter
.
Argumentem jest kontener, który umożliwia dostęp do obszaru okna i wyświetlanie zawartości.
System może automatycznie zamknąć prezentację, gdy użytkownik opuści główne okno aplikacji. Można też ją zamknąć, wywołując metodę WindowAreaSessionPresenter#close()
.
W przypadku innych wywołań zwrotnych dla uproszczenia sprawdź treść funkcji pod kątem błędów i zarejestruj jej 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, użyj oficjalnej ikony Dual Screen, aby poinformować użytkowników, jak włączyć lub wyłączyć ten tryb.
Praktyczny przykład znajdziesz w witrynie DualScreenActivity.kt.
Tryb tylnego wyświetlacza
Podobnie jak w przypadku trybu podwójnego, poniższy przykład funkcji toggleRearDisplayMode()
zamyka sesję, jeśli możliwość jest już aktywna lub w inny sposób wywołuje funkcję transferActivityToWindowArea()
:
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 element WindowAreaSessionCallback,
, który jest łatwiejszy do zaimplementowania, ponieważ wywołanie zwrotne nie otrzymuje prezentera, który umożliwia wyświetlanie treści w obszarze okna, ale 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, użyj oficjalnej ikony tylnego aparatu, aby wskazać użytkownikom, jak włączyć lub wyłączyć tryb tylnego wyświetlacza.
Dodatkowe materiały
- Ćwiczenie z programowania dotyczące rozwijania funkcji aparatu
- Podsumowanie pakietu
androidx.window.area
- Przykładowy kod Jetpack WindowManager: