I dispositivi pieghevoli offrono esperienze di visualizzazione uniche. La modalità display posteriore e la modalità doppio schermo consentono di creare funzioni di visualizzazione speciali per i dispositivi pieghevoli, come l'anteprima dei selfie con la fotocamera posteriore e display simultanei ma diversi su schermi interno ed esterno.
Modalità display posteriore
In genere quando un dispositivo pieghevole è aperto, è attivo solo lo schermo interno. La modalità display posteriore ti consente di spostare un'attività sullo schermo esterno di un dispositivo pieghevole, che solitamente è rivolto in direzione opposta all'utente mentre il dispositivo è aperto. Il display interno si spegne automaticamente.
Una nuova applicazione consiste nel visualizzare l'anteprima della fotocamera sullo schermo esterno, in modo che gli utenti possano scattare selfie con la fotocamera posteriore, che di solito offre prestazioni di scatto molto migliori.
Per attivare la modalità di visualizzazione posteriore, gli utenti rispondono a una finestra di dialogo per consentire all'app di cambiare schermo, ad esempio:
Il sistema crea la finestra di dialogo, quindi non è necessario alcun sviluppo da parte tua. Vengono visualizzate finestre di dialogo diverse a seconda dello stato del dispositivo; ad esempio, il sistema invita gli utenti a aprire il dispositivo quando questo è chiuso. La finestra di dialogo non può essere personalizzata, ma può variare su dispositivi di diversi OEM.
Puoi provare la modalità di visualizzazione posteriore con l'app della fotocamera di Pixel Fold. Dai un'occhiata a un'implementazione di esempio nel codelab Unfold your camera experience.
Modalità Dual Screen
La modalità a doppio schermo ti consente di mostrare contemporaneamente i contenuti su entrambi i display di un dispositivo pieghevole. La modalità doppio schermo è disponibile su Pixel Fold con Android 14 (livello API 34) o versioni successive.
Un esempio di caso d'uso è l'interprete Dual Screen.
Attiva le modalità in modo programmatico
Puoi accedere alla modalità di visualizzazione posteriore e a quella a doppio schermo tramite le API Jetpack WindowManager, a partire dalla versione della libreria 1.2.0-beta03.
Aggiungi la dipendenza WindowManager al file build.gradle
del modulo dell'app:
Trendy
dependencies { implementation "androidx.window:window:1.2.0-beta03" }
Kotlin
dependencies { implementation("androidx.window:window:1.2.0-beta03") }
Il punto di accesso è WindowAreaController
,
che fornisce le informazioni e il comportamento relativi allo spostamento di finestre tra i display o le aree di visualizzazione su un dispositivo.
WindowAreaController
consente di eseguire query sull'elenco di oggetti
WindowAreaInfo
disponibili.
Usa WindowAreaInfo
per accedere a WindowAreaSession
,
un'interfaccia che rappresenta una funzionalità attiva nell'area della finestra.
Utilizza WindowAreaSession
per determinare la disponibilità di uno specifico
WindowAreaCapability
.
Ogni funzionalità è correlata a una WindowAreaCapability.Operation
specifica.
Nella versione 1.2.0-beta03, Jetpack WindowManager supporta due tipi di operazioni:
WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA
, utilizzata per avviare la modalità doppio schermo.WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
, utilizzato per avviare la modalità display posteriore.
Di seguito è riportato un esempio di come dichiarare le variabili per la modalità display posteriore e doppio schermo nell'attività principale dell'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;
Ecco come inizializzare le variabili nel metodo onCreate()
della tua attività:
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; } } });
Prima di avviare un'operazione, verifica la disponibilità della funzionalità specifica:
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. }
Modalità Dual Screen
L'esempio seguente chiude la sessione se la funzionalità è già attiva, oppure chiama la funzione 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); } }
Nota l'utilizzo dell'attività principale dell'app come WindowAreaPresentationSessionCallback
.
L'API utilizza un approccio basato su listener: quando si effettua una richiesta per presentare i contenuti
all'altro display di un pieghevole, si avvia una sessione che viene restituita
tramite il metodo onSessionStarted()
del listener.
Quando chiudi la sessione, riceverai una conferma nel metodo onSessionEnded()
.
Per creare il listener, implementa l'interfaccia WindowAreaPresentationSessionCallback
:
Kotlin
class MainActivity : AppCompatActivity(), windowAreaPresentationSessionCallback
Java
public class MainActivity extends AppCompatActivity implements WindowAreaPresentationSessionCallback
Il listener deve implementare i metodi onSessionStarted()
, onSessionEnded(),
e onContainerVisibilityChanged()
.
I metodi di callback ti informano dello stato della sessione e ti consentono di aggiornare l'app di conseguenza.
Il callback onSessionStarted()
riceve un WindowAreaSessionPresenter
come argomento.
L'argomento è il contenitore che ti consente di accedere a un'area della finestra e mostrare i contenuti.
La presentazione può essere chiusa automaticamente dal sistema quando l'utente abbandona la finestra principale dell'applicazione oppure può essere chiusa chiamando il numero WindowAreaSessionPresenter#close()
.
Per gli altri callback, per semplicità, controlla se sono presenti errori nel corpo della funzione e registra lo stato:
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); }
Per mantenere la coerenza in tutto l'ecosistema, utilizza l'icona ufficiale di Dual Screen per indicare agli utenti come attivare o disattivare la modalità Dual Screen.
Per un esempio pratico, consulta il sito DualScreenActivity.kt.
Modalità display posteriore
Analogamente all'esempio della modalità a doppio schermo, l'esempio seguente di una funzione toggleRearDisplayMode()
chiude la sessione se la funzionalità è già attiva,
oppure richiama la funzione 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); } }
In questo caso, l'attività visualizzata viene utilizzata come WindowAreaSessionCallback,
, che è più semplice da implementare perché il callback non riceve un presentatore che consente di mostrare i contenuti in un'area della finestra ma trasferisce invece l'intera attività in un'altra area:
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}"); } }
Per mantenere la coerenza in tutto l'ecosistema, utilizza l'icona ufficiale della fotocamera posteriore per indicare agli utenti come attivare o disattivare la modalità display posteriore.
Risorse aggiuntive
- Codelab per Spiegare l'esperienza con la videocamera
- Riepilogo del pacchetto
androidx.window.area
- Codice di esempio per Jetpack WindowManager: