Einbetten von Aktivitäten

Durch das Einbetten von Aktivitäten werden Apps auf Geräten mit großem Display optimiert, indem das Aufgabenfenster einer Anwendung zwischen zwei Aktivitäten oder zwei Instanzen derselben Aktivität aufgeteilt wird.

Abbildung 1: App „Einstellungen“ mit Aktivitäten nebeneinander.

Wenn Ihre App aus mehreren Aktivitäten besteht, können Sie mithilfe von eingebetteten Aktivitäten die Nutzerfreundlichkeit auf Tablets, faltbaren Geräten und ChromeOS-Geräten verbessern.

Für das Einbetten von Aktivitäten ist kein Code-Refactoring erforderlich. Sie bestimmen, wie Ihre App seine Aktivitäten nebeneinander oder gestapelt anzeigen, indem Sie eine XML-Datei oder Jetpack WindowManager-API-Aufrufe ausführen.

Die Unterstützung für kleine Bildschirme wird automatisch beibehalten. Wenn Ihre App auf einem Gerät mit kleinem Bildschirm haben, sind die Aktivitäten übereinander gestapelt. Auf großen Bildschirmen werden Aktivitäten nebeneinander angezeigt. Das System bestimmt, Präsentation basierend auf der von Ihnen erstellten Konfiguration – keine Verzweigungslogik erforderlich.

Die Aktivitäts-Embeddings passen sich an die Geräteausrichtung an und funktionieren nahtlos auf faltbaren Geräten. Aktivitäten werden beim Zusammen- und Aufklappen des Geräts gestapelt und wieder entfernt.

Das Einbetten von Aktivitäten wird auf den meisten Geräten mit großem Bildschirm und Android 12L (API-Level 32) und höher unterstützt.

Aufgabenfenster teilen

Die Aktivitätseinbettung teilt das App-Aufgabenfenster in zwei Container auf: primären und sekundär. Die Container enthalten Aktivitäten, die aus der Hauptaktivität oder aus anderen Aktivitäten, die bereits in den Containern vorhanden sind.

Aktivitäten werden beim Starten im sekundären Container gestapelt. Auf kleinen Bildschirmen wird der sekundäre Container auf dem primären Container gestapelt. So entsprechen das Stapeln von Aktivitäten und die Rücknavigation der Reihenfolge der Aktivitäten, die bereits in Ihrer App implementiert sind.

Die Einbettung von Aktivitäten ermöglicht es Ihnen, Aktivitäten auf verschiedene Weise darzustellen. Ihr App kann das Aufgabenfenster teilen, indem zwei Aktivitäten nebeneinander gestartet werden gleichzeitig:

Abbildung 2: Zwei Aktivitäten nebeneinander.

Sie können auch eine neue Aktivität neben einer Aktivität starten, die das gesamte Aufgabenfenster belegt, um eine Aufteilung zu erstellen:

Abbildung 3. Aktivität A startet Aktivität B seitlich.

Aktivitäten, die sich bereits in einer geteilten Ablage befinden und ein Aufgabenfenster teilen, können gestartet werden auf folgende Arten ausführen:

  • Neben einer anderen Aktivität:

    Abbildung 4: Aktivität A startet Aktivität C seitlich über Aktivität B.
  • Sie können die Aufteilung auch seitlich verschieben, sodass die vorherige primäre Aktivität ausgeblendet wird:

    Abbildung 5: Aktivität B startet Aktivität C zur Seite und verschiebt seitlich geteilt werden.
  • eine Aktivität oben starten; Das heißt, im selben Aktivitäten-Stack:

    Abbildung 6: Aktivität B startet Aktivität C ohne zusätzliche Intent-Flags.
  • Starten Sie ein vollständiges Fenster mit einer Aktivität in derselben Aufgabe:

    Abbildung 7: Aktivität A oder Aktivität B startet Aktivität C, die das Aufgabenfenster füllt.

Rückwärtsnavigation

Je nach Abhängigkeiten zwischen Aktivitäten oder wie Nutzer das Zurück-Ereignis auslösen, können verschiedene Arten von Anwendungen unterschiedliche Regeln für die Rücknavigation im Splitscreen-Fensterstatus haben, z. B.:

  • Zusammenführung: Wenn Aktivitäten einen Bezug haben und einer der Aktivitäten nicht angezeigt werden soll ohne das andere, kann die Rückwärtsnavigation so konfiguriert werden, dass beides abgeschlossen wird.
  • Eigenständig: Wenn Aktivitäten vollständig unabhängig sind, wirkt sich die Rücknavigation bei einer Aktivität nicht auf den Status einer anderen Aktivität im Aufgabenfenster aus.

Das Zurück-Ereignis wird an die zuletzt fokussierte Aktivität gesendet, wenn die Navigation über Schaltflächen verwendet wird.

Für die Bedienung über Gesten:

  • Android 14 (API-Level 34) und niedriger: Das Zurück-Ereignis wird an die Aktivität gesendet, bei der die Geste ausgeführt wurde. Wenn Nutzer von der linken Seite des Bildschirms wischen, wird das Zurück-Ereignis an die Aktivität im linken Bereich des geteilten Fensters gesendet. Wenn Nutzende von der rechten Seite der wird das Zurück-Ereignis an die Aktivität im rechten Fensterbereich gesendet.

  • Android 15 (API-Level 35) und höher

    • Wenn Sie mehrere Aktivitäten aus derselben App ausführen, wird mit der Geste unabhängig von der Wischrichtung die oberste Aktivität beendet.

    • In Szenarien mit zwei Aktivitäten aus verschiedenen Apps (Overlay) wird das Zurück-Ereignis auf die zuletzt im Fokus stehende Aktivität gerichtet, was dem Verhalten der Schaltflächennavigation entspricht.

Layout mit mehreren Ansichten

Mit Jetpack WindowManager können Sie ein Mehrfensterbereich zum Einbetten von Aktivitäten erstellen Layout auf Geräten mit großen Bildschirmen mit Android 12L (API-Level 32) oder höher und höher einige Geräte mit älteren Plattformversionen. Vorhandene Apps, die auf mehreren Aktivitäten statt auf Fragmenten oder ansichtenbasierten Layouts wie SlidingPaneLayout basieren, können die Nutzerfreundlichkeit auf großen Bildschirmen verbessern, ohne den Quellcode umzustrukturieren.

Ein häufiges Beispiel ist die Aufteilung in Listen- und Detailansichten. Um eine qualitativ hochwertige Präsentation zu gewährleisten, startet das System die Listenaktivität und die Anwendung startet dann sofort die Detailaktivität. Das Übergangssystem wartet, bis beide Aktivitäten gezeichnet wurden, und zeigt sie dann zusammen an. Für den Nutzer sind die beiden beginnen, als eine Aktivität zu starten.

Abbildung 8: Zwei Aktivitäten wurden gleichzeitig in einem Layout mit mehreren Ansichten gestartet.

Aufgeteilte Attribute

Sie können festlegen, wie das Aufgabenfenster zwischen den aufgeteilten Containern verteilt wird und wie die Container relativ zueinander angeordnet werden.

Legen Sie für Regeln, die in einer XML-Konfigurationsdatei definiert sind, die folgenden Attribute fest:

  • splitRatio: Damit werden die Proportionen des Containers festgelegt. Der Wert ist eine Gleitkommazahl im offenen Intervall (0,0, 1,0).
  • splitLayoutDirection: Gibt an, wie die geteilten Container relativ zueinander angeordnet werden. Zu den Werten gehören:
    • ltr: von links nach rechts
    • rtl: Von rechts nach links
    • locale: Entweder ltr oder rtl wird anhand der Gebietsschemaeinstellung bestimmt.

Beispiele finden Sie im Abschnitt XML-Konfiguration.

Erstellen Sie für Regeln, die mit den WindowManager APIs erstellt wurden, ein SplitAttributes-Objekt mit SplitAttributes.Builder und rufen Sie die folgenden Buildermethoden auf:

Beispiele finden Sie im Abschnitt WindowManager API.

Abbildung 9: Zwei Aktivitätsaufteilungen, die von links nach rechts angeordnet sind, aber unterschiedliche Aufteilungsverhältnisse haben.

Platzhalter

Platzhalteraktivitäten sind leere sekundäre Aktivitäten, die einen Bereich einer Aktivitätsaufteilung. Sie sollen letztendlich durch eine andere Aktivität ersetzt werden, die Inhalte enthält. Beispielsweise könnte eine Platzhalteraktivität die sekundäre Seite einer Aktivität in einem Listendetaillayout belegen, bis ein Element aus der Liste ausgewählt wird. In diesem Fall wird der Platzhalter durch eine Aktivität mit den Detailinformationen für das ausgewählte Listenelement ersetzt.

Standardmäßig zeigt das System Platzhalter nur an, wenn genügend Platz für eine Aktivitätsaufteilung vorhanden ist. Platzhalter werden automatisch fertiggestellt, wenn die Anzeigegröße die Breite oder Höhe zu klein ist, um eine Aufteilung anzuzeigen. Wenn der Platz ausreicht, startet das System den Platzhalter mit einem zurückgesetzten Status neu.

Abbildung 10: Faltbares Gerät auf- und zuklappen. Platzhalter abgeschlossen und bei Änderungen der Anzeigegröße neu erstellt.

Das stickyPlaceholder-Attribut einer SplitPlaceholderRule- oder setSticky()-Methode von SplitPlaceholder.Builder kann das Standardverhalten jedoch überschreiben. Wenn für das Attribut oder die Methode der Wert true angegeben ist, zeigt das System den Platzhalter als oberste Aktivität im Aufgabenfenster an, wenn das Display von einem zweispaltigen zu einem einspaltigen Display minimiert wird (siehe Split-Konfiguration).

Abbildung 11. Faltbares Gerät wird zusammengeklappt und aufgeklappt. Platzhalter die Aktivität fixiert.

Fenstergrößenänderungen

Wenn sich die Gerätekonfiguration ändert und die Breite des Aufgabenfensters so reduziert wird, dass es nicht groß genug für ein mehrspaltiges Layout ist (z. B. wenn ein faltbares Gerät mit großem Bildschirm von der Größe eines Tablets auf die Größe eines Smartphones zusammengefaltet wird oder das App-Fenster im Mehrfenstermodus neu skaliert wird), werden die Aktivitäten, die keine Platzhalter sind, im sekundären Bereich des Aufgabenfensters über den Aktivitäten im primären Bereich gestapelt.

Platzhalteraktivitäten werden nur angezeigt, wenn die Anzeigebreite für eine geteilt. Auf kleineren Bildschirmen wird der Platzhalter automatisch geschlossen. Wenn der Parameter wieder groß genug wird, wird der Platzhalter neu erstellt. Weitere Informationen finden Sie im Abschnitt Platzhalter.

Das Stapeln von Aktivitäten ist möglich, weil die Aktivitäten in WindowManager z-geordnet werden im sekundären Bereich über den Aktivitäten im primären Bereich.

Mehrere Aktivitäten im sekundären Bereich

Aktivität B startet Aktivität C ohne zusätzliche Intent-Flags:

Aktivitätsaufteilung mit Aktivitäten A, B und C, wobei C eingeblendet ist
          oben auf B.

Dies führt zu der folgenden Z-Reihenfolge der Aktivitäten in derselben Aufgabe:

Sekundärer Aktivitätsstapel mit Aktivität C über Seite B.
          Der sekundäre Stapel wird über den primären Aktivitäts-Stack gestapelt
          die Aktivität A enthält.

In einem kleineren Aufgabenfenster wird die Anwendung also auf eine einzige Aktivität verkleinert, C ganz oben im Stapel:

Kleines Fenster, in dem nur Aktivität C angezeigt wird

Wenn Sie im kleineren Fenster zurücknavigieren, können Sie durch die gestapelten Aktivitäten wechseln übereinander liegen.

Wenn die Konfiguration des Aufgabenfensters auf eine größere Größe wiederhergestellt wird, mehrere Bereiche aufnehmen, werden die Aktivitäten wieder nebeneinander angezeigt.

Gestapelte Aufteilungen

Aktivität B startet Aktivität C zur Seite und verschiebt den Teil zur Seite:

Aufgabenfenster mit den Aktivitäten A und B, dann mit den Aktivitäten B und C

Das Ergebnis ist die folgende Z-Reihenfolge der Aktivitäten in derselben Aufgabe:

Die Aktivitäten A, B und C in einem Stapel. Die Aktivitäten werden von oben nach unten in der folgenden Reihenfolge gestapelt: C, B, A.

In einem kleineren Aufgabenfenster wird die Anwendung auf eine einzelne Aktivität mit C oben reduziert:

Kleines Fenster, in dem nur Aktivität C angezeigt wird

Festes Hochformat

Mit der Manifesteinstellung android:screenOrientation können Apps in das Hoch- oder Querformat hochladen. Um die Nutzererfahrung zu verbessern wie Tablets und faltbare Geräte, Gerätehersteller (OEMs) können Anfragen zur Bildschirmausrichtung ignorieren und die App im Hochformat anzeigen lassen. im Querformat oder im Querformat auf Displays im Hochformat.

Abbildung 12: Aktivitäten im Letterbox-Format: festes Hochformat auf einem Gerät im Querformat (links), festes Querformat auf einem Gerät im Hochformat (rechts)

Wenn die Aktivitäts-Embedding-Funktion aktiviert ist, können OEMs Geräte so anpassen, dass Aktivitäten im Querformat mit Letterbox-Ansicht im Hochformat auf großen Bildschirmen (Breite ≥ 600 dp) angezeigt werden. Wenn bei einer festen Aktivität im Hochformat eine zweite Aktivität gestartet wird, kann das Gerät die beiden Aktivitäten nebeneinander in einem Zweifenster anzeigen.

Abbildung 13. Bei der Aktivität A im Fix-Hochformat wird die Aktivität B seitlich gestartet.

android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED immer hinzufügen an deine App-Manifestdatei an, um Geräte darüber zu informieren, dass deine App Aktivitätseinbettung (siehe Split-Konfiguration). Abschnitt). OEM-benutzerdefinierte Geräte können dann entscheiden, im Hochformat.

Split-Konfiguration

Mit Split-Regeln können Sie Aktivitätsaufteilungen konfigurieren. Sie definieren Aufteilungsregeln in einer XML-Datei Konfigurationsdatei oder mithilfe der Jetpack-WindowManager-API Anrufe.

In beiden Fällen muss Ihre App auf die WindowManager-Bibliothek zugreifen und das System darüber informieren, dass die App die Einbettung von Aktivitäten implementiert hat.

Unternimm Folgendes:

  1. Fügen Sie der Datei build.gradle auf Modulebene Ihrer App die neueste Abhängigkeit der WindowManager-Bibliothek hinzu, z. B.:

    implementation 'androidx.window:window:1.1.0-beta02'

    Die WindowManager-Bibliothek stellt alle für die Aktivität erforderlichen Komponenten bereit. und Einbettungen.

  2. Informieren Sie das System darüber, dass Ihre App die Einbettung von Aktivitäten implementiert hat.

    Füge das Attribut android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED hinzu an <application> des App-Manifests und legen Sie den Parameter Wert auf "true" setzen. Beispiel:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <application>
            <property
                android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
                android:value="true" />
        </application>
    </manifest>
    

    Ab WindowManager-Version 1.1.0-alpha06 werden Aktivitätseinbettungen sind deaktiviert, es sei denn, die Property wird dem Manifest hinzugefügt und auf „true“ gesetzt.

    Außerdem können Gerätehersteller die Einstellung nutzen, um benutzerdefinierte Funktionen für Apps, die das Einbetten von Aktivitäten unterstützen Geräte können beispielsweise im Querformat verwenden, um die Aktivitäten für die Wechsel zu einem Zwei-Fenster-Layout, wenn eine zweite Aktivität beginnt (siehe Festes Hochformat).

XML-Konfiguration

So erstellst du eine XML-basierte Implementierung der Aktivitäts-Embedding-Funktion:

  1. Erstellen Sie eine XML-Ressourcendatei, die folgende Aufgaben erfüllt:

    • Definiert Aktivitäten, die eine Aufteilung teilen
    • Konfiguriert die Optionen für die Aufteilung
    • Erstellt einen Platzhalter für den sekundären Container der Aufteilung, wenn keine Inhalte verfügbar sind.
    • Gibt Aktivitäten an, die niemals Teil einer Aufteilung sein sollten

    Beispiel:

    <!-- main_split_config.xml -->
    
    <resources
        xmlns:window="http://schemas.android.com/apk/res-auto">
    
        <!-- Define a split for the named activities. -->
        <SplitPairRule
            window:splitRatio="0.33"
            window:splitLayoutDirection="locale"
            window:splitMinWidthDp="840"
            window:splitMaxAspectRatioInPortrait="alwaysAllow"
            window:finishPrimaryWithSecondary="never"
            window:finishSecondaryWithPrimary="always"
            window:clearTop="false">
            <SplitPairFilter
                window:primaryActivityName=".ListActivity"
                window:secondaryActivityName=".DetailActivity"/>
        </SplitPairRule>
    
        <!-- Specify a placeholder for the secondary container when content is
             not available. -->
        <SplitPlaceholderRule
            window:placeholderActivityName=".PlaceholderActivity"
            window:splitRatio="0.33"
            window:splitLayoutDirection="locale"
            window:splitMinWidthDp="840"
            window:splitMaxAspectRatioInPortrait="alwaysAllow"
            window:stickyPlaceholder="false">
            <ActivityFilter
                window:activityName=".ListActivity"/>
        </SplitPlaceholderRule>
    
        <!-- Define activities that should never be part of a split. Note: Takes
             precedence over other split rules for the activity named in the
             rule. -->
        <ActivityRule
            window:alwaysExpand="true">
            <ActivityFilter
                window:activityName=".ExpandedActivity"/>
        </ActivityRule>
    
    </resources>
    
  2. Erstellen Sie einen Initialisierer.

    Die Komponente „WindowManager“ RuleController analysiert die XML-Konfigurationsdatei und stellt die Regeln dem System zur Verfügung. Eine Jetpack-Start-Bibliothek Initializer stellt die XML-Datei beim Starten der App für RuleController zur Verfügung, damit die Regeln beim Starten von Aktivitäten in Kraft treten.

    So erstellen Sie einen Initiierer:

    1. Fügen Sie die neueste Abhängigkeit der Jetpack Startup-Bibliothek zu Ihrer Modulebene hinzu. build.gradle-Datei. Beispiel:

      implementation 'androidx.startup:startup-runtime:1.1.1'

    2. Erstellen Sie eine Klasse, die die Initializer-Schnittstelle implementiert.

      Der Initialisierer stellt die Split-Regeln für RuleController bereit, indem er die ID der XML-Konfigurationsdatei (main_split_config.xml) an die RuleController.parseRules()-Methode übergibt.

      Kotlin

      class SplitInitializer : Initializer<RuleController> {
      
          override fun create(context: Context): RuleController {
              return RuleController.getInstance(context).apply {
                  setRules(RuleController.parseRules(context, R.xml.main_split_config))
              }
          }
      
          override fun dependencies(): List<Class<out Initializer<*>>> {
              return emptyList()
          }
      }

      Java

      public class SplitInitializer implements Initializer<RuleController> {
      
           @NonNull
           @Override
           public RuleController create(@NonNull Context context) {
               RuleController ruleController = RuleController.getInstance(context);
               ruleController.setRules(
                   RuleController.parseRules(context, R.xml.main_split_config)
               );
               return ruleController;
           }
      
           @NonNull
           @Override
           public List<Class<? extends Initializer<?>>> dependencies() {
               return Collections.emptyList();
           }
      }
  3. Erstellen Sie einen Contentanbieter für die Regeldefinitionen.

    androidx.startup.InitializationProvider der App-Manifestdatei hinzufügen als <provider>. Geben Sie einen Verweis auf die Implementierung Ihrer RuleController-Initialisierer, SplitInitializer:

    <!-- AndroidManifest.xml -->
    
    <provider android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <!-- Make SplitInitializer discoverable by InitializationProvider. -->
        <meta-data android:name="${applicationId}.SplitInitializer"
            android:value="androidx.startup" />
    </provider>
    

    InitializationProvider erkennt und initialisiert SplitInitializer vor dem wird die Methode onCreate() der App aufgerufen. Daher befinden sich die Aufteilungsregeln wenn die Hauptaktivität der App beginnt.

WindowManager API

Sie können das Einbetten von Aktivitäten mit wenigen API-Aufrufen programmgesteuert implementieren. Führen Sie die Aufrufe in der onCreate()-Methode einer Unterklasse von Application aus, damit die Regeln in Kraft sind, bevor Aktivitäten gestartet werden.

So erstellen Sie programmatisch eine Aktivitätsaufteilung:

  1. So erstellen Sie eine Split-Regel:

    1. SplitPairFilter erstellen der die Aktivitäten identifiziert, die sich der Aufteilung teilen:

      Kotlin

      val splitPairFilter = SplitPairFilter(
         ComponentName(this, ListActivity::class.java),
         ComponentName(this, DetailActivity::class.java),
         null
      )

      Java

      SplitPairFilter splitPairFilter = new SplitPairFilter(
         new ComponentName(this, ListActivity.class),
         new ComponentName(this, DetailActivity.class),
         null
      );
    2. Fügen Sie den Filter einem Filtersatz hinzu:

      Kotlin

      val filterSet = setOf(splitPairFilter)

      Java

      Set<SplitPairFilter> filterSet = new HashSet<>();
      filterSet.add(splitPairFilter);
    3. Erstellen Sie Layoutattribute für die Aufteilung:

      Kotlin

      val splitAttributes: SplitAttributes = SplitAttributes.Builder()
          .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
          .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
          .build()

      Java

      final SplitAttributes splitAttributes = new SplitAttributes.Builder()
            .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
            .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
            .build();

      Mit SplitAttributes.Builder wird ein Objekt mit Layoutattributen erstellt:

      • setSplitType(): Hiermit wird festgelegt, wie der verfügbare Anzeigebereich den einzelnen Aktivitätscontainern zugewiesen wird. Der Verhältnisaufteilungstyp gibt den Anteil des verfügbaren Display-Bereichs, der dem Primärcontainer; belegt der sekundäre Container den Rest den verfügbaren Anzeigebereich.
      • setLayoutDirection(): Gibt an, wie die Aktivitätscontainer relativ zueinander angeordnet werden, zuerst der primäre Container.
    4. SplitPairRule erstellen:

      Kotlin

      val splitPairRule = SplitPairRule.Builder(filterSet)
          .setDefaultSplitAttributes(splitAttributes)
          .setMinWidthDp(840)
          .setMinSmallestWidthDp(600)
          .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
          .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER)
          .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS)
          .setClearTop(false)
          .build()

      Java

      SplitPairRule splitPairRule = new SplitPairRule.Builder(filterSet)
          .setDefaultSplitAttributes(splitAttributes)
          .setMinWidthDp(840)
          .setMinSmallestWidthDp(600)
          .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
          .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER)
          .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS)
          .setClearTop(false)
          .build();

      SplitPairRule.Builder erstellt und konfiguriert die Regel:

      • filterSet: enthält Split-Pair-Filter, die bestimmen, wann die Regel anwenden, indem Aktivitäten identifiziert werden, die eine Aufteilung aufweisen.
      • setDefaultSplitAttributes(): Wendet Layoutattribute auf die Regel.
      • setMinWidthDp(): Hiermit wird die minimale Anzeigebreite festgelegt (in dichteunabhängige Pixel, dp), die eine Aufteilung ermöglichen.
      • setMinSmallestWidthDp(): Legt den Mindestwert (in dp) fest, den die kleinere der beiden Displayabmessungen haben muss, um unabhängig von der Geräteausrichtung eine Aufteilung zu ermöglichen.
      • setMaxAspectRatioInPortrait(): Hiermit wird das maximale Seitenverhältnis (Höhe:Breite) für die Hochformatanzeige festgelegt, bei der Aktivitätsaufschlüsselungen angezeigt werden. Wenn das Seitenverhältnis eines Hochformat-Displays das maximale Seitenverhältnis überschreitet, werden Splitscreens unabhängig von der Breite des Displays deaktiviert. Hinweis: Der Standardwert ist 1,4. Das bedeutet, dass Aktivitäten auf den meisten Tablets im Hochformat das gesamte Aufgabenfenster einnehmen. Siehe auch SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT und setMaxAspectRatioInLandscape() Der Standardwert für Querformat ist ALWAYS_ALLOW.
      • setFinishPrimaryWithSecondary(): Legt fest, wie fertig sind. die Aktivitäten im sekundären Container auf die Aktivitäten im primären Container. NEVER gibt an, dass das System die primären Aktivitäten nicht beenden soll, wenn alle Aktivitäten im sekundären Container abgeschlossen sind (siehe Aktivitäten beenden).
      • setFinishSecondaryWithPrimary(): Hiermit wird festgelegt, wie sich das Beenden aller Aktivitäten im primären Container auf die Aktivitäten im sekundären Container auswirkt. ALWAYS gibt an, dass das System immer Schließen Sie die Aktivitäten im sekundären Container ab, wenn alle Aktivitäten in der Ausführung des primären Containers (siehe Aktivitäten beenden) ausführen.
      • setClearTop(): Gibt an, ob alle Aktivitäten im sekundäre Container abgeschlossen sind, wenn eine neue Aktivität in Container. Ein false-Wert gibt an, dass neue Aktivitäten über den Aktivitäten, die sich bereits im sekundären Container befinden.
    5. Rufen Sie die Singleton-Instanz von WindowManager RuleController ab, und füge die folgende Regel hinzu:

      Kotlin

        val ruleController = RuleController.getInstance(this)
        ruleController.addRule(splitPairRule)
        

      Java

        RuleController ruleController = RuleController.getInstance(this);
        ruleController.addRule(splitPairRule);
        
  2. Erstelle einen Platzhalter für den sekundären Container, wenn Inhalte nicht verfügbar sind:

    1. Erstelle ein ActivityFilter-Element, das die Aktivität identifiziert, mit der Der Platzhalter teilt eine Aufteilung des Aufgabenfensters mit:

      Kotlin

      val placeholderActivityFilter = ActivityFilter(
          ComponentName(this, ListActivity::class.java),
          null
      )

      Java

      ActivityFilter placeholderActivityFilter = new ActivityFilter(
          new ComponentName(this, ListActivity.class),
          null
      );
    2. Fügen Sie den Filter einem Filtersatz hinzu:

      Kotlin

      val placeholderActivityFilterSet = setOf(placeholderActivityFilter)

      Java

      Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>();
      placeholderActivityFilterSet.add(placeholderActivityFilter);
    3. Erstellen: SplitPlaceholderRule:

      Kotlin

      val splitPlaceholderRule = SplitPlaceholderRule.Builder(
            placeholderActivityFilterSet,
            Intent(context, PlaceholderActivity::class.java)
          ).setDefaultSplitAttributes(splitAttributes)
           .setMinWidthDp(840)
           .setMinSmallestWidthDp(600)
           .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
           .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS)
           .setSticky(false)
           .build()

      Java

      SplitPlaceholderRule splitPlaceholderRule = new SplitPlaceholderRule.Builder(
            placeholderActivityFilterSet,
            new Intent(context, PlaceholderActivity.class)
          ).setDefaultSplitAttributes(splitAttributes)
           .setMinWidthDp(840)
           .setMinSmallestWidthDp(600)
           .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
           .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS)
           .setSticky(false)
           .build();

      SplitPlaceholderRule.Builder erstellt und konfiguriert die Regel:

      • placeholderActivityFilterSet: Enthält Aktivitätsfilter, mit denen festgelegt wird, wann die Regel angewendet werden soll. Dazu werden Aktivitäten angegeben, mit denen die Platzhalteraktivität verknüpft ist.
      • Intent: Gibt den Start der Platzhalteraktivität an.
      • setDefaultSplitAttributes(): Wendet Layoutattribute auf die Regel an.
      • setMinWidthDp(): Mit dieser Einstellung wird die Mindestbreite des Displays (in dichteunabhängigen Pixeln, dp) festgelegt, ab der eine Aufteilung möglich ist.
      • setMinSmallestWidthDp(): Legt den Mindestwert (in dp) fest, mit dem der kleinere der beiden angezeigt wird Die Abmessungen müssen unabhängig vom Gerät eine Aufteilung ermöglichen Ausrichtung.
      • setMaxAspectRatioInPortrait(): Mit diesem Attribut wird das maximale Seitenverhältnis (Höhe:Breite) für die Hochformatanzeige festgelegt, bei der Aktivitätsaufschlüsselungen angezeigt werden. Hinweis: Das Der Standardwert ist 1,4, was dazu führt, dass Aktivitäten die Aufgabe ausführen. auf den meisten Tablets im Hochformat. Siehe auch SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT und setMaxAspectRatioInLandscape() Der Standardwert für das Querformat ist ALWAYS_ALLOW.
      • setFinishPrimaryWithPlaceholder(): Legt fest, wie sich das Beenden der Platzhalteraktivität auf die Aktivitäten auswirkt im primären Container. „IMMER“ gibt an, dass das System die Aktivitäten im primären Container immer beenden soll, wenn der Platzhalter abgeschlossen ist (siehe Aktivitäten beenden).
      • setSticky(): Hiermit wird festgelegt, ob die Platzhalteraktivität wird auf kleinen Displays oben im Aktivitätsstapel angezeigt, sobald das Symbol Platzhalter wurde zuerst in einer Aufteilung mit ausreichender Mindestzahl angezeigt Breite.
    4. Fügen Sie die Regel dem WindowManager RuleController hinzu:

      Kotlin

      ruleController.addRule(splitPlaceholderRule)

      Java

      ruleController.addRule(splitPlaceholderRule);
  3. Geben Sie Aktivitäten an, die niemals Teil einer Aufteilung sein sollten:

    1. Erstellen Sie eine ActivityFilter, die eine Aktivität identifiziert, die immer den gesamten Bereich für die Aufgabenanzeige einnehmen soll:

      Kotlin

      val expandedActivityFilter = ActivityFilter(
        ComponentName(this, ExpandedActivity::class.java),
        null
      )

      Java

      ActivityFilter expandedActivityFilter = new ActivityFilter(
        new ComponentName(this, ExpandedActivity.class),
        null
      );
    2. Fügen Sie den Filter einem Filtersatz hinzu:

      Kotlin

      val expandedActivityFilterSet = setOf(expandedActivityFilter)

      Java

      Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>();
      expandedActivityFilterSet.add(expandedActivityFilter);
    3. ActivityRule erstellen:

      Kotlin

      val activityRule = ActivityRule.Builder(expandedActivityFilterSet)
          .setAlwaysExpand(true)
          .build()

      Java

      ActivityRule activityRule = new ActivityRule.Builder(
          expandedActivityFilterSet
      ).setAlwaysExpand(true)
       .build();

      ActivityRule.Builder erstellt und konfiguriert die Regel:

      • expandedActivityFilterSet: Enthält Aktivitätsfilter, mit denen Sie festlegen, wann die Regel angewendet werden soll. Dazu werden Aktivitäten angegeben, die von der Aufteilung ausgeschlossen werden sollen.
      • setAlwaysExpand(): Gibt an, ob die Aktivität das gesamte Aufgabenfenster aus.
    4. Fügen Sie die Regel dem WindowManager RuleController hinzu:

      Kotlin

      ruleController.addRule(activityRule)

      Java

      ruleController.addRule(activityRule);

Anwendungsübergreifende Einbettung

Unter Android 13 (API-Level 33) und höher können Apps Aktivitäten von anderen Apps. Anwendungsübergreifende oder übergreifende UID, Einbettung von Aktivitäten ermöglicht die visuelle Integration von Aktivitäten aus verschiedenen Android-Apps. Die eine Aktivität der Host-App und eine eingebettete Aktivität eine andere App auf dem Bildschirm nebeneinander oder oben und unten auf dem Bildschirm Aktivitätseinbettung.

So könnte die Einstellungen-App beispielsweise die Aktivität der Hintergrundauswahl aus der App „WallpaperPicker“ einbetten:

Abbildung 14. Die Einstellungen-App (Menü links) mit der Auswahl für Hintergründe als eingebettete Aktivität (rechts).

Vertrauensmodell

Hostprozesse, die Aktivitäten aus anderen Apps einbetten, können die Darstellung der eingebetteten Aktivitäten, einschließlich Größe, Position, Zuschneiden und Transparenz. Böswillige Hosts können diese Funktion nutzen, um Nutzer zu täuschen und Clickjacking oder andere Angriffe auf die Benutzeroberfläche durchzuführen.

Damit der Missbrauch eingebetteter App-Aktivitäten verhindert wird, müssen Apps bei Android diese Option aktivieren um die Einbettung ihrer Aktivitäten zu ermöglichen. Apps können Hosts als vertrauenswürdig oder nicht vertrauenswürdig kennzeichnen.

Vertrauenswürdige Hosts

Um es anderen Anwendungen zu ermöglichen, die Darstellung von Aktivitäten aus deiner App zu entfernen, gib das SHA-256-Zertifikat des Hosts an im Attribut android:knownActivityEmbeddingCerts des <activity>- oder <application>-Elemente der Manifestdatei deiner App.

Legen Sie den Wert von android:knownActivityEmbeddingCerts entweder als String fest:

<activity
    android:name=".MyEmbeddableActivity"
    android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
    ... />

oder, um mehrere Zertifikate anzugeben, ein String-Array:

<activity
    android:name=".MyEmbeddableActivity"
    android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
    ... />

der auf eine Ressource wie die folgende verweist:

<resources>
    <string-array name="known_host_certificate_digests">
      <item>cert1</item>
      <item>cert2</item>
      ...
    </string-array>
</resources>

App-Inhaber können Gradle ausführen, um einen SHA-Zertifikat-Digest zu erhalten. signingReport Aufgabe. Der Zertifikats-Digest ist der SHA-256-Fingerabdruck ohne die Trennpunkte. Weitere Informationen finden Sie unter Bericht zur Signatur ausführen und Client authentifizieren.

Nicht vertrauenswürdige Hosts

Wenn Sie zulassen möchten, dass andere Apps die Aktivitäten Ihrer App einbetten und deren Darstellung steuern können, geben Sie das Attribut android:allowUntrustedActivityEmbedding in den Elementen <activity> oder <application> im App-Manifest an. Beispiel:

<activity
    android:name=".MyEmbeddableActivity"
    android:allowUntrustedActivityEmbedding="true"
    ... />

Der Standardwert des Attributs ist „false“, wodurch App-übergreifende Aktivitäten verhindert werden. und Einbettungen.

Benutzerdefinierte Authentifizierung

Um die Risiken von nicht vertrauenswürdigen eingebetteten Aktivitäten zu minimieren, erstellen Sie einen benutzerdefinierten Authentifizierungsmechanismus, der die Identität des Hosts überprüft. Wenn Sie die Hostzertifikate kennen, verwenden Sie die androidx.security.app.authenticator-Bibliothek, um sich zu authentifizieren. Wenn sich der Host nach dem Einbetten Ihrer Aktivität authentifiziert, können Sie die tatsächlichen Inhalte anzeigen. Falls nicht, können Sie die Nutzenden darüber informieren, und den Inhalt blockieren.

Mit der Methode ActivityEmbeddingController#isActivityEmbedded() aus der Jetpack WindowManager-Bibliothek kannst du prüfen, ob ein Host deine Aktivität einbettet, z. B. so:

Kotlin

fun isActivityEmbedded(activity: Activity): Boolean {
    return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity)
}

Java

boolean isActivityEmbedded(Activity activity) {
    return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity);
}

Mindestgröße

Das Android-System wendet die im App-Manifest-Element <layout> angegebene minimale Höhe und Breite auf eingebettete Aktivitäten an. Wenn für eine Anwendung keine Mindesthöhe und ‑breite angegeben ist, gelten die Standardwerte des Systems (sw220dp).

Wenn der Host versucht, die Größe des eingebetteten Containers auf eine Größe kleiner als das Minimum zu ändern, wird der eingebettete Container so erweitert, dass er die gesamten Aufgabengrenzen einnimmt.

<Aktivitätsalias>

Damit das Einbetten vertrauenswürdiger oder nicht vertrauenswürdiger Aktivitäten mit dem Element <activity-alias> funktioniert, muss android:knownActivityEmbeddingCerts oder android:allowUntrustedActivityEmbedding auf die Zielaktivität und nicht auf den Alias angewendet werden. Die Richtlinie, die die Sicherheit des Systemservers überprüft, ist basierend auf den Flags, die für das Ziel festgelegt sind, und nicht auf dem Alias.

Hostanwendung

Hostanwendungen implementieren das Einbetten von App-übergreifenden Aktivitäten auf die gleiche Weise wie das Einbetten von Aktivitäten in einer einzelnen App. Mit den Objekten SplitPairRule und SplitPairFilter oder ActivityRule und ActivityFilter werden eingebettete Aktivitäten und Aufgabenfensteraufteilungen angegeben. Split-Regeln werden statisch in XML oder zur Laufzeit mithilfe von Jetpack WindowManager API-Aufrufen definiert.

Wenn eine Host-Anwendung versucht, eine Aktivität einzubetten, für die sie App-übergreifende Einbettung nimmt die Aktivität die gesamten Aufgabengrenzen ein. Daher müssen Hostanwendungen wissen, ob das Einbetten in andere Apps für die Zielaktivitäten zulässig ist.

Wenn eine eingebettete Aktivität eine neue Aktivität in derselben Aufgabe startet und die neue App-übergreifende Einbettung wird nicht aktiviert, die Aktivität innerhalb der Aufgabengrenzen, anstatt die Aktivität im eingebetteten Container zu überlagern.

Eine Host-Anwendung kann ihre eigenen Aktivitäten uneingeschränkt einbetten, wenn die Aktivitäten in derselben Aufgabe starten.

Beispiele für Split-Tests

Vom ganzen Fenster teilen

Abbildung 15. Aktivität A startet Aktivität B seitlich.

Kein Refactoring erforderlich. Sie können die Konfiguration für die Aufteilung statisch oder zur Laufzeit definieren und dann Context#startActivity() ohne zusätzliche Parameter aufrufen.

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Standardmäßig aufteilen

Wenn die Landingpage einer App in zwei Teile geteilt werden soll Container auf großen Bildschirmen verwenden, ist die User Experience am besten, wenn beide Aktivitäten gleichzeitig erstellt und präsentiert werden. Inhalte sind für den sekundären Container der Aufteilung jedoch möglicherweise erst verfügbar, wenn der Nutzer mit der Aktivität im primären Container interagiert, z. B. ein Element aus einem Navigationsmenü auswählt. Eine Platzhalteraktivität kann die Lücke füllen, bis Inhalte im sekundären Container der Aufteilung angezeigt werden können (siehe Abschnitt Platzhalter).

Abbildung 16. Die Aufteilung wurde durch gleichzeitiges Öffnen von zwei Aktivitäten erstellt. Eine Aktivität ist ein Platzhalter.

Wenn Sie eine Aufteilung mit einem Platzhalter erstellen möchten, erstellen Sie einen Platzhalter und verknüpfen Sie ihn mit der primären Aktivität:

<SplitPlaceholderRule
    window:placeholderActivityName=".PlaceholderActivity">
    <ActivityFilter
        window:activityName=".MainActivity"/>
</SplitPlaceholderRule>

Wenn eine App einen Intent empfängt, kann die Zielaktivität als sekundärer Teil einer Aktivitätsaufteilung; z. B. eine Anfrage, ein Detail anzuzeigen, mit Informationen zu einem Element aus einer Liste. Auf kleinen Displays sind die Details wird im vollständigen Aufgabenfenster angezeigt. auf größeren Geräten neben der Liste.

Abbildung 17: Die Deeplink-Detailaktivität wird alleine auf einem kleinen Bildschirm angezeigt, sondern zusammen mit einer Liste der Aktivitäten auf einem großen Bildschirm.

Die Startanfrage sollte an die Hauptaktivität und die Zieldetails weitergeleitet werden. sollte in einem Split gestartet werden. Das System wählt automatisch die richtige Präsentation – gestapelt oder nebeneinander – basierend auf den verfügbaren Anzeigebreite.

Kotlin

override fun onCreate(savedInstanceState Bundle?) {
    . . .
    RuleController.getInstance(this)
        .addRule(SplitPairRule.Builder(filterSet).build())
    startActivity(Intent(this, DetailActivity::class.java))
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    . . .
    RuleController.getInstance(this)
        .addRule(new SplitPairRule.Builder(filterSet).build());
    startActivity(new Intent(this, DetailActivity.class));
}

Das Deeplink-Ziel ist möglicherweise die einzige Aktivität, die für die Nutzenden im Rückwärts-Navigationsstapel sind, und Sie sollten vermeiden, die Detailaktivität und lassen Sie nur die Hauptaktivität:

Großes Display mit Listen- und Detailaktivitäten nebeneinander.
          Bei der Rückwärtsnavigation können Details zu Aktivitäten nicht geschlossen und die Listenaktivitäten nicht auf dem Bildschirm beibehalten werden.

Kleines Display nur mit Detailaktivität. Rückwärtsnavigation nicht möglich
          Detailaktivität schließen und Listenaktivität anzeigen.

Stattdessen können Sie beide Aktivitäten gleichzeitig abschließen, indem Sie das Attribut finishPrimaryWithSecondary verwenden:

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".ListActivity"
        window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>

Weitere Informationen finden Sie im Abschnitt Konfigurationsattribute.

Mehrere Aktivitäten in aufgeteilten Containern

Durch das Stapeln mehrerer Aktivitäten in einem geteilten Container können Nutzer tief Inhalte. Bei einer Aufteilung in Listen- und Detailansicht muss der Nutzer beispielsweise möglicherweise einen untergeordneten Detailbereich aufrufen, die Hauptaktivität aber beibehalten:

Abbildung 18: Aktivität, die im sekundären Bereich des Aufgabenfensters geöffnet wurde

Kotlin

class DetailActivity {
    . . .
    fun onOpenSubDetail() {
      startActivity(Intent(this, SubDetailActivity::class.java))
    }
}

Java

public class DetailActivity {
    . . .
    void onOpenSubDetail() {
        startActivity(new Intent(this, SubDetailActivity.class));
    }
}

Die Unterdetailaktivität wird über der Detailaktivität platziert und blendet sie aus:

Der Nutzer kann dann zur vorherigen Detailebene zurückkehren, über den Stack:

Abbildung 19: Aktivität wurde aus der obersten Ebene des Stapels entfernt.

Das Stapeln von Aktivitäten übereinander ist das Standardverhalten, wenn Aktivitäten über eine Aktivität im selben sekundären Container gestartet werden. Aktivitäten die aus dem primären Container in einem aktiven Split gestartet werden, sekundärer Container oben im Aktivitätsstapel.

Aktivitäten in einer neuen Aufgabe

Wenn Aktivitäten in einem geteilten Aufgabenfenster Aktivitäten in einer neuen Aufgabe starten, ist die neue Aufgabe unabhängig von der Aufgabe, die die Aufteilung enthält, und wird im Vollfenster angezeigt. Auf dem Bildschirm „Letzte“ werden zwei Aufgaben angezeigt: die Aufgabe in der Aufteilung und die neue Aufgabe.

Abbildung 20. Beginnen Sie Aktivität C in einer neuen Aufgabe aus Aktivität B.

Aktivität ersetzen

Aktivitäten können im sekundären Container-Stack ersetzt werden, z. B. wenn die primäre Aktivität für die Navigation auf oberster Ebene verwendet wird und die sekundäre Aktivität ein ausgewähltes Ziel ist. Jede Auswahl aus der Navigation auf oberster Ebene sollte eine neue Aktivität im sekundären Container starten und die vorherigen Aktivitäten entfernen.

Abbildung 21. Navigationsaktivität der obersten Ebene im primären Bereich Zielaktivitäten im sekundären Bereich ersetzt.

Wenn die App die Aktivität nicht im sekundären Container beendet, wenn der Änderungen an der Navigationsauswahl, könnte die Rückwärtsnavigation verwirrend sein, im zusammengeklappten Zustand minimiert ist. Wenn Sie z. B. ein Menü in der primären Bereich und die Bildschirme A und B im sekundären Bereich gestapelt, klappt das Smartphone zusammen, B befindet sich auf A und A befindet sich über dem Menü. Wenn der Nutzer von B zurückgeht, wird anstelle des Menüs A angezeigt.

In solchen Fällen muss Bildschirm A aus dem Backstack entfernt werden.

Standardmäßig werden beim Starten in einem neuen Container über einer vorhandenen Spaltung die neuen sekundären Container oben platziert und die alten im Hintergrundstapel beibehalten. Sie können die Aufteilungen so konfigurieren, dass die vorherigen sekundären Container mit clearTop gelöscht und neue Aktivitäten normal gestartet werden.

<SplitPairRule
    window:clearTop="true">
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenA"/>
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>

Kotlin

class MenuActivity {
    . . .
    fun onMenuItemSelected(selectedMenuItem: Int) {
        startActivity(Intent(this, classForItem(selectedMenuItem)))
    }
}

Java

public class MenuActivity {
    . . .
    void onMenuItemSelected(int selectedMenuItem) {
        startActivity(new Intent(this, classForItem(selectedMenuItem)));
    }
}

Alternativ können Sie dieselbe sekundäre Aktivität verwenden und von der primären (Menü-)Aktivität neue Intents senden, die auf dieselbe Instanz verweisen, aber einen Status- oder UI-Update im sekundären Container auslösen.

Mehrere Aufteilungen

Apps können eine mehrstufige Tiefennavigation bieten, indem zusätzliche Aktivitäten gestartet werden beiseite.

Startet eine Aktivität in einem sekundären Container eine neue Aktivität neben der Seite, wird eine neue Aufteilung über die vorhandene Aufteilung erstellt.

Abbildung 22. Aktivität B startet Aktivität C daneben.

Der Backstack enthält alle zuvor geöffneten Aktivitäten, sodass Nutzer nach Abschluss von C zur A/B-Testverzweigung wechseln können.

Aktivitäten A, B und C in einem Stapel Die Aktivitäten werden von oben nach unten in der folgenden Reihenfolge gestapelt: C, B, A.

Um eine neue Aufteilung zu erstellen, starten Sie die neue Aktivität neben der bestehenden sekundärer Container. Deklarieren Sie die Konfigurationen sowohl für die A/B- als auch für die B/C-Aufteilung und starten Sie Aktivität C wie gewohnt über B:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
    <SplitPairFilter
        window:primaryActivityName=".B"
        window:secondaryActivityName=".C"/>
</SplitPairRule>

Kotlin

class B {
    . . .
    fun onOpenC() {
        startActivity(Intent(this, C::class.java))
    }
}

Java

public class B {
    . . .
    void onOpenC() {
        startActivity(new Intent(this, C.class));
    }
}

Auf Statusänderungen reagieren

Verschiedene Aktivitäten in einer App können UI-Elemente haben, die dieselbe Funktion haben Funktion; z. B. ein Steuerelement, das ein Fenster mit Einstellungen.

Abbildung 23. Verschiedene Aktivitäten mit funktional identischen UI-Elementen

Wenn zwei Aktivitäten, die ein UI-Element gemeinsam haben, sich in einem Split befinden, ist es und es möglicherweise verwirrend ist, das Element in beiden Aktivitäten anzuzeigen.

Abbildung 24. Doppelte UI-Elemente in der Aktivitätsaufteilung.

Wenn Sie wissen möchten, wann sich Aktivitäten in einem Split befinden, prüfen Sie den Fluss SplitController.splitInfoList oder registrieren Sie einen Listener mit SplitControllerCallbackAdapter für Änderungen am Split-Status. Passen Sie dann die Benutzeroberfläche entsprechend an:

Kotlin

val layout = layoutInflater.inflate(R.layout.activity_main, null)
val view = layout.findViewById<View>(R.id.infoButton)
lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        splitController.splitInfoList(this@SplitDeviceActivity) // The activity instance.
            .collect { list ->
                view.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE
            }
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    . . .
    new SplitControllerCallbackAdapter(SplitController.getInstance(this))
        .addSplitListener(
            this,
            Runnable::run,
            splitInfoList -> {
                View layout = getLayoutInflater().inflate(R.layout.activity_main, null);
                layout.findViewById(R.id.infoButton).setVisibility(
                    splitInfoList.isEmpty() ? View.VISIBLE : View.GONE);
            });
}

Coroutinen können in jedem Lebenszyklusstatus gestartet werden, werden aber in der Regel im Status STARTED gestartet, um Ressourcen zu sparen. Weitere Informationen finden Sie unter Kotlin-Coroutinen mit lebenszyklusbewussten Komponenten verwenden.

Callbacks können in jedem Lebenszyklusstatus erfolgen, auch wenn eine Aktivität angehalten. Hörer sollten in der Regel in onStart() registriert und in onStop() nicht registriert sein.

Modales Fenster im Vollbildmodus

Bei einigen Aktivitäten können Nutzer erst dann mit der Anwendung interagieren, wenn eine bestimmte Aktion ausgeführt wurde, z. B. eine Aktivität auf dem Anmeldebildschirm, ein Bildschirm zur Bestätigung der Richtlinien oder eine Fehlermeldung. Modale Aktivitäten sollten nicht in einem Split angezeigt werden.

Sie können erzwingen, dass eine Aktivität immer das Aufgabenfenster ausfüllt, indem Sie die Schaltfläche zum Maximieren verwenden Konfiguration:

<ActivityRule
    window:alwaysExpand="true">
    <ActivityFilter
        window:activityName=".FullWidthActivity"/>
</ActivityRule>

Aktivitäten abschließen

Nutzer können Aktivitäten auf beiden Seiten des geteilten Bereichs beenden, indem sie vom Rand wischen. des Bildschirms:

Abbildung 25: Wischgeste zum Beenden von Aktivität B.
Abbildung 26. Wischgeste zum Beenden von Aktivität A.

Wenn das Gerät so eingerichtet ist, dass die Schaltfläche „Zurück“ anstelle der Bedienung über Gesten verwendet wird, wird die Eingabe an die fokussierte Aktivität gesendet, d. h. die Aktivität, die berührt oder zuletzt eingeführt.

Der Effekt, dass das Beenden aller Aktivitäten in einem Container auf die jeweils andere Seite wirkt hängt von der Split-Konfiguration ab.

Konfigurationsattribute

Sie können Regelattribute für Aufteilungspaare angeben, um zu konfigurieren, wie das Fertigstellen die Aktivitäten auf der einen Seite der Teilung sich auf die Aktivitäten auf der anderen Seite der der Spaltung. Die Attribute sind:

  • window:finishPrimaryWithSecondary – Wie sich das Abschließen aller Aktivitäten im sekundären Container auf die Aktivitäten im primären Container auswirkt
  • window:finishSecondaryWithPrimary – Abschluss aller Aktivitäten in Der primäre Container wirkt sich auf die Aktivitäten im sekundären Container aus.

Mögliche Werte der Attribute:

  • always: Die Aktivitäten im zugehörigen Container werden immer beendet.
  • never: Die Aktivitäten im zugehörigen Container werden nie beendet.
  • adjacent: Die Aktivitäten im zugehörigen Container werden beendet, wenn werden die beiden Container nebeneinander angezeigt, aber nicht, wenn der Zwei Behälter sind gestapelt

Beispiel:

<SplitPairRule
    &lt;!-- Do not finish primary container activities when all secondary container activities finish. --&gt;
    window:finishPrimaryWithSecondary="never"
    &lt;!-- Finish secondary container activities when all primary container activities finish. --&gt;
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Standardkonfiguration

Wenn alle Aktivitäten in einem Container eines Splits abgeschlossen sind, wird der verbleibende Container das gesamte Fenster ausfüllt:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Aufteilung mit den Aktivitäten A und B. A ist fertig und B nimmt das gesamte Fenster ein.

Aufteilung mit den Aktivitäten A und B. B abgeschlossen ist, sodass A bis
          das gesamte Fenster einnimmt.

Aktivitäten gemeinsam beenden

Aktivitäten im primären Container automatisch beenden, wenn alle Aktivitäten im sekundären Container abgeschlossen sind:

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Aufteilung mit den Aktivitäten A und B. B ist abgeschlossen, wodurch auch A abgeschlossen wird und das Aufgabenfenster leer bleibt.

Aufteilung mit den Aktivitäten A und B. A ist beendet, B bleibt in diesem Fall.
          im Aufgabenfenster aus.

Schließen Sie die Aktivitäten automatisch im sekundären Container ab, wenn alle Aktivitäten im primären Container wurden beendet:

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Aufteilung mit den Aktivitäten A und B A ist abgeschlossen, wodurch auch B beendet wird und das Aufgabenfenster leer bleibt.

Aufteilung mit den Aktivitäten A und B. B ist fertig, aber A bleibt allein.
          im Aufgabenfenster aus.

Schließen Sie Aktivitäten gemeinsam ab, wenn alle Aktivitäten in der primären oder Abschluss des sekundären Containers:

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Aufteilung mit den Aktivitäten A und B A ist abgeschlossen, wodurch auch B beendet wird und das Aufgabenfenster leer bleibt.

Aufteilung mit den Aktivitäten A und B. B beendet ist, was auch
          beendet A und lässt das Aufgabenfenster leer.

Mehrere Aktivitäten in Containern abschließen

Wenn mehrere Aktivitäten in einem geteilten Container gestapelt sind, wird eine Aktivität beendet unten im Stapel beenden Aktivitäten nicht automatisch oben.

Wenn sich beispielsweise zwei Aktivitäten im sekundären Container befinden, C über B:

Sekundärer Aktivitätsstapel mit Aktivität C über Seite B
          wird über den praktischen Aktivitäten-Stack gestapelt, der die Aktivität enthält.

Die Konfiguration der Aufteilung wird durch die Konfiguration der Aktivitäten A und B definiert:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Beim Abschließen der obersten Aktivität wird die Aufteilung beibehalten.

Mit Aktivität A im primären Container und Aktivitäten B und C im primären Container aufteilen
          das zweite, C über B gestapelt. C ist fertig und A und B bleiben in der Aktivitätsaufteilung.

Durch das Abschließen der unteren (Stamm-)Aktivität des sekundären Containers wird das Element nicht entfernt. die darauf aufbauenden Aktivitäten; und behält so auch die Aufteilung bei.

Mit Aktivität A im primären Container und Aktivitäten B und C im primären Container aufteilen
          das zweite, C über B gestapelt. B ist fertig und A und C bleiben in der Aktivitätsaufteilung.

Alle zusätzlichen Regeln für das gemeinsame Abschließen von Aktivitäten, z. B. das Abschließen der sekundären Aktivität mit der primären, werden ebenfalls ausgeführt:

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Aufteilung mit Aktivität A im primären Container und Aktivitäten B und C im sekundären Container, wobei C auf B gestapelt ist. A ist fertig und damit auch B und C.

Und wenn die Aufteilung so konfiguriert ist, dass die primäre und die sekundäre Instanz zusammen abgeschlossen werden:

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Mit Aktivität A im primären Container und Aktivitäten B und C im primären Container aufteilen
          das zweite, C über B gestapelt. C ist fertig und A und B bleiben in der Aktivitätsaufteilung.

Aufteilung mit Aktivität A im primären Container und Aktivitäten B und C im sekundären Container, wobei C über B gestapelt ist. B beendet, wobei A und C
          Aktivitätsaufteilung.

Mit Aktivität A im primären Container und Aktivitäten B und C im primären Container aufteilen
          das zweite, C über B gestapelt. Ende A, Ende B und Ende
          C)

Aufteilungsattribute während der Laufzeit ändern

Die Eigenschaften einer aktiven und sichtbaren Aufteilung können nicht geändert werden. Ändern der wirken sich Aufteilungsregeln auf zusätzliche Aktivitäten und neue Container aus, aber nicht vorhandene und aktive Aufteilungen.

Um die Eigenschaften aktiver Aufteilungen zu ändern, schließen Sie die Nebenaktivität ab oder und dann mit einer neuen Konfiguration wieder an der Seite starten.

Eigenschaften mit dynamischer Aufteilung

Android 15 (API-Level 35) und höher, unterstützt von Jetpack WindowManager 1.4 und höher, bieten dynamische Funktionen, mit denen sich die Aufteilung von eingebetteten Aktivitäten konfigurieren lässt. Dazu gehören:

  • Bereichserweiterung: Mit einem interaktiven, verschiebbaren Trennstrich können Nutzer die Bereiche in einer geteilten Präsentation anpassen.
  • Anpinnen von Aktivitäten:Nutzer können Inhalte in einem Container anpinnen und Isolieren Sie die Navigation im Container von der Navigation im anderen Container.
  • Abdunkeln von Vollbilddialogfeldern: Beim Einblenden eines Dialogfelds können Apps angeben, ob das gesamte Aufgabenfenster oder nur der Container abgedunkelt werden soll, über den das Dialogfeld geöffnet wurde.

Bereich maximieren

Mit der Ansichtserweiterung können Nutzer die Bildschirmfläche anpassen, die den beiden Aktivitäten in einem Layout mit zwei Ansichten zugewiesen ist.

So passen Sie das Aussehen des Fensterteilers an und legen den Bereich fest, in dem er verschoben werden kann:

  1. Instanz von DividerAttributes erstellen

  2. Passen Sie die Trennlinienattribute an:

    • color:Die Farbe des ziehbaren Bereichstrennzeichens.

    • widthDp:Breite des ziehbaren Bereichstrennzeichens. Festlegen auf WIDTH_SYSTEM_DEFAULT, damit die Trennlinie vom System bestimmt werden kann Breite.

    • Ziehbereich:Dies ist der minimale Prozentsatz des Bildschirms, der in beiden Bereichen angezeigt werden kann. besetzt sind. Kann zwischen 0,33 und 0,66 liegen. Festlegen auf DRAG_RANGE_SYSTEM_DEFAULT, damit das System den Ziehpunkt bestimmen kann Bereich.

Kotlin

val splitAttributesBuilder: SplitAttributes.Builder = SplitAttributes.Builder()
    .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
    .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)

if (WindowSdkExtensions.getInstance().extensionVersion >= 6) {
    splitAttributesBuilder.setDividerAttributes(
      DividerAttributes.DraggableDividerAttributes.Builder()
        .setColor(getColor(context, R.color.divider_color))
        .setWidthDp(4)
        .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT)
        .build()
    )
}
val splitAttributes: SplitAttributes = splitAttributesBuilder.build()

Java

SplitAttributes.Builder splitAttributesBuilder = new SplitAttributes.Builder()
    .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
    .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT);

if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) {
    splitAttributesBuilder.setDividerAttributes(
      new DividerAttributes.DraggableDividerAttributes.Builder()
        .setColor(ContextCompat.getColor(context, R.color.divider_color))
        .setWidthDp(4)
        .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT)
        .build()
    );
}
SplitAttributes splitAttributes = splitAttributesBuilder.build();

Anpinnen von Aktivitäten

Mit der Aktivitäts-Anpinning-Funktion können Nutzer eines der geteilten Fenster anpinnen, damit die Aktivität unverändert bleibt, während sie im anderen Fenster navigieren. Aktivität Anpinnen bietet ein verbessertes Multitasking.

So aktivieren Sie die Funktion zum Anpinnen von Aktivitäten in Ihrer App:

  1. Fügen Sie der Layoutdatei der Aktivität, die Sie anpinnen möchten, eine Schaltfläche hinzu, z. B. die Detailaktivität eines Listendetaillayouts:

    <androidx.constraintlayout.widget.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/detailActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/white"
     tools:context=".DetailActivity">
    
    <TextView
       android:id="@+id/textViewItemDetail"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textSize="36sp"
       android:textColor="@color/obsidian"
       app:layout_constraintBottom_toTopOf="@id/pinButton"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />
    
    <androidx.appcompat.widget.AppCompatButton
       android:id="@+id/pinButton"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/pin_this_activity"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@id/textViewItemDetail"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
  2. Legen Sie in der onCreate()-Methode der Aktivität einen "onclick"-Listener auf der Schaltfläche:

    Kotlin

    pinButton = findViewById(R.id.pinButton)
    pinButton.setOnClickListener {
        val splitAttributes: SplitAttributes = SplitAttributes.Builder()
            .setSplitType(SplitAttributes.SplitType.ratio(0.66f))
            .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
            .build()
    
        val pinSplitRule = SplitPinRule.Builder()
            .setSticky(true)
            .setDefaultSplitAttributes(splitAttributes)
            .build()
    
        SplitController.getInstance(applicationContext).pinTopActivityStack(taskId, pinSplitRule)
    }

    Java

    Button pinButton = findViewById(R.id.pinButton);
    pinButton.setOnClickListener( (view) => {
        SplitAttributes splitAttributes = new SplitAttributes.Builder()
            .setSplitType(SplitAttributes.SplitType.ratio(0.66f))
            .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
            .build();
    
        SplitPinRule pinSplitRule = new SplitPinRule.Builder()
            .setSticky(true)
            .setDefaultSplitAttributes(splitAttributes)
            .build();
    
        SplitController.getInstance(getApplicationContext()).pinTopActivityStack(getTaskId(), pinSplitRule);
    });

Vollbild dimmen

Bei Aktivitäten werden die Displays in der Regel gedimmt, um die Aufmerksamkeit auf einen Dialog zu lenken. In sollten beide Bereiche des zweiteiligen Bildschirms gedimmt werden, nur den Bereich mit der Aktivität, mit der das Dialogfeld geöffnet wurde, für eine einheitliche Benutzeroberfläche Nutzererfahrung.

Bei WindowManager 1.4 und höher wird das gesamte App-Fenster standardmäßig gedimmt, wenn ein wird geöffnet (siehe EmbeddingConfiguration.DimAreaBehavior.ON_TASK).

Wenn Sie nur den Container der Aktivität dimmen möchten, durch die das Dialogfeld geöffnet wurde, verwenden Sie EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK.

Aktivität aus einem geteilten Fenster in ein Vollbildfenster extrahieren

Erstellen Sie eine neue Konfiguration, die das vollständige Fenster der Nebenaktivität anzeigt, und Starten Sie die Aktivität mit einem Intent neu, der in dieselbe Instanz aufgelöst wird.

Unterstützung von Aufteilungen während der Laufzeit prüfen

Die Einbettung von Aktivitäten wird unter Android 12L (API-Level 32) und höher unterstützt, ist aber auch auf einigen Geräten mit älteren Plattformversionen verfügbar. Wenn Sie die Verfügbarkeit der Funktion zur Laufzeit prüfen möchten, verwenden Sie das Attribut SplitController.splitSupportStatus oder die Methode SplitController.getSplitSupportStatus():

Kotlin

if (SplitController.getInstance(this).splitSupportStatus ==
     SplitController.SplitSupportStatus.SPLIT_AVAILABLE) {
     // Device supports split activity features.
}

Java

if (SplitController.getInstance(this).getSplitSupportStatus() ==
     SplitController.SplitSupportStatus.SPLIT_AVAILABLE) {
     // Device supports split activity features.
}

Wenn Aufteilungen nicht unterstützt werden, werden Aktivitäten über dem Aktivitätsstapel gestartet (gemäß dem Modell für das Einbetten von Inhalten ohne Aktivität).

Systemüberschreibung verhindern

Die Hersteller von Android-Geräten (Erstausrüster, OEMs) können die Einbettung von Aktivitäten als Funktion des Gerätesystems implementieren. Die gibt das System Aufteilungsregeln für Apps mit mehreren Aktivitäten an, wodurch das Windowing überschrieben wird. Verhalten der Apps. Durch die Systemüberschreibung werden Apps mit mehreren Aktivitäten in einen systemdefinierten Aktivitäts-Embedding-Modus gezwungen.

Die Einbettung von Systemaktivitäten kann die App-Darstellung durch mehrspaltige Layouts wie Liste-Detail verbessern, ohne dass Änderungen an der App vorgenommen werden müssen. Die Einbettung von Systemaktivitäten kann jedoch auch zu falschen App-Layouts, Fehlern oder Konflikten mit der von der App implementierten Einbettung von Aktivitäten führen.

Ihre App kann das Einbetten von Systemaktivitäten verhindern oder zulassen, indem Sie eine Property in der Manifestdatei der App festlegen, z. B.:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <property
            android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
            android:value="true|false" />
    </application>
</manifest>

Der Property-Name wird in Jetpack WindowManager WindowProperties definiert. -Objekt enthält. Setzen Sie den Wert auf false, wenn in Ihrer App Aktivitätseinbettungen implementiert sind. Wenn Sie anderweitig verhindern möchten, dass das System seine Aktivitätseinbettung anwendet Regeln für Ihre App. Legen Sie den Wert auf true fest, damit das System diese anwenden kann systemdefinierten Aktivitäten in deine App einzubetten.

Einschränkungen und Vorbehalte

  • Nur die Host-App der Aufgabe, die als Inhaber der Stammaktivität in der Aufgabe angegeben ist, kann andere Aktivitäten in der Aufgabe organisieren und einbetten. Wenn Aktivitäten, die das Einbetten und Aufteilen unterstützen, in einer Aufgabe ausgeführt werden, die zu einer anderen Anwendung gehört, funktionieren das Einbetten und Aufteilen für diese Aktivitäten nicht.
  • Aktivitäten können nur innerhalb einer einzelnen Aufgabe organisiert werden. Aktivität starten in einer neuen Aufgabe immer in einem neuen maximierten Fenster bereits vorhandenen Aufteilungen.
  • Nur Aktivitäten im selben Prozess können organisiert und aufgeteilt werden. Der SplitInfo-Callback meldet nur Aktivitäten, die zum selben Prozess gehören, da keine Informationen zu Aktivitäten in anderen Prozessen verfügbar sind.
  • Jede Paar- oder einzelne Aktivitätsregel gilt nur für Aktivitätsstarts, die nachdem die Regel registriert wurde. Es gibt derzeit keine Möglichkeit, vorhandene Aufteilungen oder ihre visuellen Eigenschaften zu aktualisieren.
  • Die Filterkonfiguration für das Split-Pair-Tracking muss mit den Intents übereinstimmen, die beim vollständigen Starten von Aktivitäten verwendet werden. Der Abgleich erfolgt an dem Punkt, an dem ein neuer die Aktivität während des Bewerbungsprozesses gestartet wird, Komponentennamen, die später im Systemprozess aufgelöst werden, impliziten Intents. Wenn der Name einer Komponente zum Zeitpunkt der Einführung nicht bekannt ist, kann stattdessen ein Platzhalter („*/*“) verwendet und die Filterung basierend auf der Intent-Aktion durchgeführt werden.
  • Es ist derzeit nicht möglich, Aktivitäten nach der Erstellung zwischen Containern oder zwischen Aufteilungen zu verschieben. Teilungen werden von der WindowManager-Bibliothek nur erstellt, wenn neue Aktivitäten mit übereinstimmenden Regeln gestartet werden. Sie werden wieder gelöscht, wenn die letzte Aktivität in einem Teilcontainer beendet ist.
  • Aktivitäten können neu gestartet werden, wenn sich die Konfiguration ändert. erstellt oder entfernt wird und sich die Aktivitätsgrenzen ändern, kann die Aktivität durch vollständiges Löschen der vorherigen Instanz und Erstellen der neuen. Daher sollten App-Entwickler vorsichtig sein, wenn sie beispielsweise neue Aktivitäten über Lebenszyklus-Callbacks starten.
  • Geräte müssen die Benutzeroberfläche für Fenstererweiterungen enthalten, um das Einbetten von Aktivitäten zu unterstützen. Fast alle Geräte mit großem Display mit Android 12L (API-Level) 32) oder höher enthalten die Schnittstelle. Einige Geräte mit großem Display, auf denen nicht mehrere Aktivitäten ausgeführt werden können, haben jedoch keine Benutzeroberfläche für Fenstererweiterungen. Wenn ein Gerät mit großem Bildschirm den Multifenstermodus nicht unterstützt, wird möglicherweise auch das Einbetten von Aktivitäten nicht unterstützt.

Weitere Informationen