Faltbare Geräte bieten ein einzigartiges Nutzererlebnis. Mit dem Modus für das hintere Display und dem Dual Screen-Modus können Sie spezielle Displayfunktionen für faltbare Geräte entwickeln, z. B. eine Vorschau für Rückkamera-Selfies und die gleichzeitige Anzeige unterschiedlicher Inhalte auf dem inneren und äußeren Display.
Modus für das hintere Display
Wenn ein faltbares Gerät aufgeklappt ist, ist normalerweise nur das innere Display aktiv. Im Modus für das hintere Display können Sie eine Aktivität auf das äußere Display eines faltbaren Geräts verschieben. Dieses ist normalerweise vom Nutzer abgewandt, wenn das Gerät aufgeklappt ist. Das innere Display wird automatisch ausgeschaltet.
Eine neue Anwendung ist die Anzeige der Kameravorschau auf dem äußeren Display. So können Nutzer Selfies mit der Rückkamera aufnehmen, die in der Regel eine viel bessere Bildqualität als die Frontkamera bietet.
Wenn Nutzer den Modus für das hintere Display aktivieren möchten, müssen sie in einem Dialogfeld bestätigen, dass die App die Displays wechseln darf. Beispiel:
Das Dialogfeld wird vom System erstellt. Sie müssen also nichts entwickeln. Je nach Gerätestatus werden unterschiedliche Dialogfelder angezeigt. Wenn das Gerät beispielsweise geschlossen ist, werden Nutzer aufgefordert, es aufzuklappen. Sie können das Dialogfeld nicht anpassen. Es kann auf Geräten verschiedener Erstausrüster unterschiedlich aussehen.
Sie können den Modus für das hintere Display mit der Kamera-App des Pixel Fold ausprobieren. Eine Beispiel implementierung finden Sie im Codelab Optimize your camera app on foldable devices with Jetpack WindowManager.
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 dem Pixel Fold mit Android 14 (API-Level 34) oder höher verfügbar.
Ein Anwendungsbeispiel ist der Dual Screen-Dolmetscher.
Modi programmatisch aktivieren
Sie können ab der Bibliotheksversion 1.2.0-beta03 über die Jetpack WindowManager APIs auf den Modus für das hintere Display und den Dual Screen-Modus zugreifen.
Fügen Sie der Datei build.gradle des Moduls Ihrer App die WindowManager-Abhängigkeit hinzu:
Kotlin
dependencies {
// Define window_version in your project's build configuration.
implementation("androidx.window:window:$window_version")
}
Groovy
dependencies {
// TODO: Define window_version in your project's build configuration.
implementation "androidx.window:window:$window_version"
}
Der Einstiegspunkt ist der WindowAreaController. Er enthält die
Informationen und das Verhalten im Zusammenhang mit dem Verschieben von Fenstern zwischen Displays oder zwischen
Displaybereichen auf einem Gerät. Mit WindowAreaController können Sie die Liste der
verfügbaren WindowAreaInfo-Objekte abfragen.
Verwenden Sie WindowAreaInfo, um auf WindowAreaSession zuzugreifen, eine Schnittstelle, die
eine aktive Fensterbereichsfunktion darstellt. Mit WindowAreaSession können Sie
die Verfügbarkeit einer bestimmten WindowAreaCapability ermitteln.
Jede Funktion ist mit einer bestimmten WindowAreaCapability.Operation verknüpft.
In Version 1.2.0-beta03 unterstützt Jetpack WindowManager zwei Arten von Vorgängen:
WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREAzum Starten des Dual Screen-ModusWindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREAzum Starten des Modus für das hintere Display
Hier sehen Sie ein Beispiel dafür, wie Sie Variablen für den Modus für das hintere Display und den Dual Screen-Modus in der Hauptaktivität Ihrer App deklarieren:
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;
}
}
});
Prüfen Sie vor dem Starten eines Vorgangs 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 presentContentOnWindowArea() Funktion 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 das
WindowAreaPresentationSessionCallback-Argument verwendet wird.
Die API verwendet einen Listener-Ansatz: Wenn Sie eine Anfrage senden, um die Inhalte
auf dem anderen Display eines faltbaren Geräts zu präsentieren, starten Sie eine Sitzung, die zurückgegeben wird
über die Methode onSessionStarted() des Listeners. Wenn Sie die
Sitzung schließen, erhalten Sie eine Bestätigung in der onSessionEnded() Methode.
Implementieren Sie die WindowAreaPresentationSessionCallback
Schnittstelle, um den Listener zu erstellen:
Kotlin
class ExampleActivity : ComponentActivity(), WindowAreaPresentationSessionCallback {
Java
public class MainActivity extends AppCompatActivity implements WindowAreaPresentationSessionCallback
Der Listener muss die onSessionStarted(), onSessionEnded(),
und onContainerVisibilityChanged() Methoden implementieren. Die Callback-Methoden informieren Sie über den Sitzungsstatus und ermöglichen es Ihnen, die App entsprechend zu aktualisieren.
Der onSessionStarted() Callback erhält ein WindowAreaSessionPresenter als
Argument. Das Argument ist der Container, mit dem 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 kann sie
durch Aufrufen von WindowAreaSessionPresenter#close() geschlossen werden.
Bei den anderen Callbacks prüfen Sie zur Vereinfachung einfach im Funktionskörper auf Fehler und protokollieren Sie den Status:
Kotlin
override fun onSessionStarted(session: WindowAreaSessionPresenter) { windowAreaSession = session session.setContentView(ComposeView(session.context).apply { setContent { MyScreen() } }) } 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);
}
Um die Konsistenz im gesamten Ökosystem zu gewährleisten, verwenden Sie das offizielle Symbol fürDual Screen , um Nutzern zu zeigen, wie sie den Dual Screen-Modus aktivieren oder deaktivieren.
Ein funktionierendes Beispiel finden Sie unter DualScreenActivity.kt.
Modus für das hintere Display
Ähnlich wie im Beispiel für den Dual Screen-Modus wird im folgenden Beispiel einer
toggleRearDisplayMode() Funktion die Sitzung geschlossen, wenn die Funktion bereits
aktiv ist. Andernfalls wird die transferActivityToWindowArea()
Funktion aufgerufen:
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 toggleRearDisplayMode() {
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.
Die Rear Display API verwendet einen Listener-Ansatz: Wenn Sie anfordern, dass die Inhalte auf das andere Display verschoben werden, starten Sie eine Sitzung, die über die Methode onSessionStarted() des Listeners zurückgegeben wird. Wenn Sie stattdessen zum inneren (und größeren) Display zurückkehren möchten, schließen Sie die Sitzung und erhalten eine Bestätigung in der Methode onSessionEnded().
Kotlin
override fun onSessionStarted(session: WindowAreaSession) { 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}");
}
}
Um die Konsistenz im gesamten Ökosystem zu gewährleisten, verwenden Sie das offizielle Symbol für die Rückkamera, um Nutzern zu zeigen, wie sie den Modus für das hintere Display aktivieren oder deaktivieren.
Zusätzliche Ressourcen
- Codelab Optimize your camera app on foldable devices with Jetpack WindowManager
androidx.window.areaZusammenfassung des Pakets- Jetpack WindowManager-Beispielcode: