Faltbare Geräte bieten ein einzigartiges Videoerlebnis. Mit dem Rückdisplay- und Dual-Screen-Modus kannst du spezielle Displayfunktionen für faltbare Geräte entwickeln, z. B. eine Rückkamera-Selfie-Vorschau und gleichzeitig verschiedene Displays auf dem inneren und äußeren Display.
Rückkameramodus
Wenn ein faltbares Gerät aufgeklappt ist, ist in der Regel nur das innere Display aktiv. Im Modus „Display nach hinten“ können Sie eine Aktivität auf das äußere Display eines faltbaren Geräts verschieben, das normalerweise vom Nutzer weg zeigt, wenn das Gerät aufgeklappt ist. Das innere Display wird automatisch ausgeschaltet.
Eine neue Anwendung besteht darin, die Kameravorschau auf dem äußeren Display anzuzeigen. So können Nutzer mit der Rückkamera Selfies aufnehmen, was normalerweise eine deutlich bessere Bildleistung als mit der Frontkamera bietet.
Um den Modus für das Rückscheiben-Display zu aktivieren, müssen Nutzer in einem Dialogfeld der App erlauben, den Bildschirm zu wechseln, z. B.:
Der Dialog wird vom System erstellt, sodass keine Entwicklung Ihrerseits erforderlich ist. Je nach Gerätestatus werden unterschiedliche Dialogfelder angezeigt. Wenn das Gerät beispielsweise geschlossen ist, werden Nutzer aufgefordert, es zu öffnen. Sie können das Dialogfeld nicht anpassen und es kann auf Geräten verschiedener OEMs variieren.
Du kannst den Rückdisplaymodus mit der Kamera-App von Pixel Fold ausprobieren. Eine Beispielimplementierung findest du im Codelab Kamera-App auf faltbaren Geräten mit Jetpack WindowManager optimieren.
Dual-Screen-Modus
Im Dual Screen-Modus können Sie Inhalte gleichzeitig auf beiden Displays eines faltbaren Geräts anzeigen. Der Dual-Screen-Modus ist auf Google Pixel Fold mit Android 14 (API-Level 34) oder höher verfügbar.
Ein Beispiel für einen Anwendungsfall ist der Dual Screen-Dolmetscher.
Modi programmatisch aktivieren
Ab Bibliotheksversion 1.2.0-beta03 können Sie über die Jetpack WindowManager APIs auf den Modus für das Rückkameradisplay und den Modus für den Dualscreen zugreifen.
Fügen Sie der Moduldatei build.gradle
Ihrer App die Abhängigkeit „WindowManager“ hinzu:
Cool
dependencies { implementation "androidx.window:window:1.2.0-beta03" }
Kotlin
dependencies { implementation("androidx.window:window:1.2.0-beta03") }
Der Einstiegspunkt ist das WindowAreaController
, das Informationen und das Verhalten zum Verschieben von Fenstern zwischen Displays oder zwischen Displaybereichen auf einem Gerät bereitstellt. Mit WindowAreaController
kannst du die Liste der verfügbaren WindowAreaInfo
-Objekte abfragen.
Mit WindowAreaInfo
können Sie auf WindowAreaSession
zugreifen, eine Benutzeroberfläche, die eine Funktion für den aktiven Fensterbereich darstellt. Mit WindowAreaSession
kannst du die Verfügbarkeit einer bestimmten WindowAreaCapability
ermitteln.
Jede Funktion bezieht sich auf eine bestimmte WindowAreaCapability.Operation
.
In Version 1.2.0-beta03 unterstützt Jetpack WindowManager zwei Arten von Vorgängen:
WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA
, mit dem der Dual Screen-Modus gestartet wirdWindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
, um den Modus für das Rückscheibendisplay zu starten
Hier ist ein Beispiel für die Deklaration von Variablen für den Modus „Rückseite“ und „Dual-Screen-Modus“ in der Hauptaktivität deiner App:
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;
So initialisieren Sie die Variablen in der Methode onCreate()
Ihrer Aktivität:
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; } } });
Bevor Sie einen Vorgang starten, prüfen Sie die Verfügbarkeit der jeweiligen Funktion:
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. }
Dual Screen-Modus
Im folgenden Beispiel wird die Sitzung geschlossen, wenn die Funktion bereits aktiv ist. Andernfalls wird die Funktion presentContentOnWindowArea()
aufgerufen:
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); } }
Beachten Sie, dass die Hauptaktivität der App als Argument für WindowAreaPresentationSessionCallback
verwendet wird.
Die API verwendet einen Listener-Ansatz: Wenn Sie eine Anfrage stellen, um die Inhalte auf dem anderen Display eines faltbaren Geräts anzuzeigen, initiieren Sie eine Sitzung, die über die onSessionStarted()
-Methode des Listeners zurückgegeben wird. Wenn du die Sitzung schließt, erhältst du eine Bestätigung in der Methode onSessionEnded()
.
Implementieren Sie zum Erstellen des Listeners die Schnittstelle WindowAreaPresentationSessionCallback
:
Kotlin
class MainActivity : AppCompatActivity(), windowAreaPresentationSessionCallback
Java
public class MainActivity extends AppCompatActivity implements WindowAreaPresentationSessionCallback
Der Listener muss die Methoden onSessionStarted()
, onSessionEnded(),
und onContainerVisibilityChanged()
implementieren. Die Rückrufmethoden informieren Sie über den Sitzungsstatus und ermöglichen es Ihnen, die App entsprechend zu aktualisieren.
Der onSessionStarted()
-Callback empfängt WindowAreaSessionPresenter
als Argument. Das Argument ist der Container, über den Sie auf einen Fensterbereich zugreifen und Inhalte anzeigen können. Die Präsentation kann automatisch vom System geschlossen werden, wenn der Nutzer das primäre Anwendungsfenster verlässt. Alternativ lässt sie sich durch Aufrufen von WindowAreaSessionPresenter#close()
schließen.
Bei den anderen Callbacks prüfen Sie zur Vereinfachung einfach im Funktionskörper auf Fehler und loggen Sie den Status:
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); }
Verwenden Sie zur Einheitlichkeit im gesamten System das offizielle Dual Screen-Symbol, um Nutzern zu zeigen, wie sie den Dual-Screen-Modus aktivieren oder deaktivieren.
Ein funktionierendes Beispiel finden Sie unter DualScreenActivity.kt.
Rückdisplaymodus
Ähnlich wie im Beispiel für den Dual-Screen-Modus schließt das folgende Beispiel einer toggleRearDisplayMode()
-Funktion die Sitzung, wenn die Funktion bereits aktiv ist, oder ruft anderweitig die Funktion transferActivityToWindowArea()
auf:
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); } }
In diesem Fall wird die angezeigte Aktivität als WindowAreaSessionCallback
verwendet, was einfacher zu implementieren ist, da der Callback keinen Vortragenden empfängt, der die Anzeige von Inhalten in einem Fensterbereich zulässt. Stattdessen wird die gesamte Aktivität in einen anderen Bereich übertragen:
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}"); } }
Verwende das offizielle Symbol für die Rückkamera, um Nutzer darüber zu informieren, wie sie den Rückdisplaymodus aktivieren oder deaktivieren können.
Weitere Informationen
- Codelab zum Optimieren Ihrer Kamera-App auf faltbaren Geräten mit Jetpack WindowManager
- Paketübersicht
androidx.window.area
- Beispielcode für Jetpack WindowManager: