Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b809c7a authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "[AE Flicker Test] From a rtl split B|A, launch rtl PlaceholderPrimary...

Merge "[AE Flicker Test] From a rtl split B|A, launch rtl PlaceholderPrimary and PlaceholderSecondary. Expect PlaceholderSecondary|PlaceholderPrimary to cover B|A." into udc-qpr-dev am: 0c86688b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23302520



Change-Id: If5d62000cc298064fbc4858cb9f939ad1e1de7da
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 61787ac3 0c86688b
Loading
Loading
Loading
Loading
+211 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm.flicker.activityembedding

import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized

/**
 * Test launching a placeholder split over a normal split, both splits are configured in RTL.
 *
 * Setup: From A launch a split in RTL - resulting in B|A.
 * Transitions:
 * From A start PlaceholderPrimary, which is configured to launch with PlaceholderSecondary in RTL.
 * Expect split PlaceholderSecondary|PlaceholderPrimary covering split B|A.
 *
 * To run this test: `atest FlickerTests:RTLStartSecondaryWithPlaceholderTest`
 */
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class RTLStartSecondaryWithPlaceholderTest(flicker: FlickerTest) :
  ActivityEmbeddingTestBase(flicker) {

  /** {@inheritDoc} */
  override val transition: FlickerBuilder.() -> Unit = {
    setup {
      tapl.setExpectedRotationCheckEnabled(false)
      testApp.launchViaIntent(wmHelper)
      testApp.launchSecondaryActivityRTL(wmHelper)
    }
    transitions {
      testApp.launchPlaceholderSplitRTL(wmHelper)
    }
    teardown {
      tapl.goHome()
      testApp.exit(wmHelper)
    }
  }

  /**
   * Main activity and Secondary activity will become invisible because they are covered by
   * PlaceholderPrimary activity and PlaceholderSecondary activity.
   */
  @Presubmit
  @Test
  fun assertWindowVisibilities() {
    flicker.assertWm {
      isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
              .then()
              .isAppWindowInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
    }
    flicker.assertWm {
      isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
              .then()
              .isAppWindowInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
    }
    flicker.assertWm {
      isAppWindowInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
              .then()
              .isAppWindowVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
    }
    flicker.assertWm {
      isAppWindowInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
              .then()
              .isAppWindowVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
    }
  }

  /**
   * Main activity and Secondary activity will become invisible because they are covered by
   * PlaceholderPrimary activity and PlaceholderSecondary activity.
   */
  @Presubmit
  @Test
  fun assertLayerVisibilities() {
    flicker.assertLayers {
      this.isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
              .then()
              .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
    }
    flicker.assertLayers {
      this.isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
              .then()
              .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
    }
    flicker.assertLayers {
      isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
              .then()
              .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
    }
    flicker.assertLayers {
      isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
              .then()
              .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
    }
  }

  /** Main activity and Secondary activity split is in right-to-left layout direction. */
  @Presubmit
  @Test
  fun assertWMRTLBeforeTransition() {
    flicker.assertWmStart {
      val mainActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
      val secondaryActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
      mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
      // secondary activity is on the left, main activity is on the right.
      check { "isRTLBeforeTransition" }
              .that(mainActivityRegion.region.bounds.left)
              .isEqual(secondaryActivityRegion.region.bounds.right)
    }
  }

  /** Main activity and Secondary activity split is in right-to-left layout direction. */
  @Presubmit
  @Test
  fun assertLayerRTLBeforeTransition() {
    flicker.assertLayersStart {
      val mainActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
      val secondaryActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
      mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
      // secondary activity is on the left, main activity is on the right.
      check { "isRTLBeforeTransition" }
              .that(mainActivityRegion.region.bounds.left)
              .isEqual(secondaryActivityRegion.region.bounds.right)
    }
  }

  /**
   * PlaceholderPrimary activity and PlaceholderSecondary activity split are in right-to-left
   * layout direction.
   */
  @Presubmit
  @Test
  fun assertWMRTLAfterTransition() {
    flicker.assertWmEnd {
      val mainActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
      val secondaryActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
      mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
      // secondary activity is on the left, main activity is on the right.
      check { "isRTLBeforeTransition" }
              .that(mainActivityRegion.region.bounds.left)
              .isEqual(secondaryActivityRegion.region.bounds.right)
    }
  }

  /**
   * PlaceholderPrimary activity and PlaceholderSecondary activity split are in right-to-left
   * layout direction.
   */
  @Presubmit
  @Test
  fun assertLayerRTLAfterTransition() {
    flicker.assertLayersEnd {
      val mainActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
      val secondaryActivityRegion =
              this.visibleRegion(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
      mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
      // Placeholder secondary activity is on the left, placeholder primary activity is on the
      // right.
      check { "isRTLAfterTransition" }
              .that(mainActivityRegion.region.bounds.left)
              .isEqual(secondaryActivityRegion.region.bounds.right)
    }
  }

  companion object {
    /**
     * Creates the test configurations.
     *
     * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
     * navigation modes.
     */
    @Parameterized.Parameters(name = "{0}")
    @JvmStatic
    fun getParams(): Collection<FlickerTest> {
      return FlickerTestFactory.nonRotationTests()
    }
  }
}
+46 −0
Original line number Diff line number Diff line
@@ -100,6 +100,29 @@ constructor(
                .waitForAndVerify()
    }

    /**
     * Clicks the button to launch the secondary activity in RTL, which should split with the main
     * activity based on the split pair rule.
     */
    fun launchSecondaryActivityRTL(wmHelper: WindowManagerStateHelper) {
        val launchButton =
                uiDevice.wait(
                        Until.findObject(
                                By.res(getPackage(),
                                        "launch_secondary_activity_rtl_button")),
                        FIND_TIMEOUT
                )
        require(launchButton != null) {
            "Can't find launch secondary activity rtl button on screen."
        }
        launchButton.click()
        wmHelper
                .StateSyncBuilder()
                .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
                .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
                .waitForAndVerify()
    }

    /**
     * Clicks the button to launch the placeholder primary activity, which should launch the
     * placeholder secondary activity based on the placeholder rule.
@@ -119,6 +142,29 @@ constructor(
            .waitForAndVerify()
    }

    /**
     * Clicks the button to launch the placeholder primary activity in RTL, which should launch the
     * placeholder secondary activity based on the placeholder rule.
     */
    fun launchPlaceholderSplitRTL(wmHelper: WindowManagerStateHelper) {
        val launchButton =
                uiDevice.wait(
                        Until.findObject(
                                By.res(getPackage(),
                                        "launch_placeholder_split_rtl_button")),
                        FIND_TIMEOUT
                )
        require(launchButton != null) {
            "Can't find launch placeholder split button on screen."
        }
        launchButton.click()
        wmHelper
                .StateSyncBuilder()
                .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, PlatformConsts.STATE_RESUMED)
                .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, PlatformConsts.STATE_RESUMED)
                .waitForAndVerify()
    }

    companion object {
        private const val TAG = "ActivityEmbeddingAppHelper"

+3 −1
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@
    <application android:allowBackup="false"
                 android:supportsRtl="true">
        <uses-library android:name="androidx.window.extensions" android:required="false"/>

        <property
            android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
            android:value="true" />
        <activity android:name=".SimpleActivity"
                  android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
                  android:theme="@style/CutoutShortEdges"
+18 −3
Original line number Diff line number Diff line
@@ -25,24 +25,39 @@
        android:id="@+id/launch_secondary_activity_button"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_centerHorizontal="true"
        android:onClick="launchSecondaryActivity"
        android:tag="LEFT_TO_RIGHT"
        android:text="Launch Secondary Activity" />

    <Button
        android:id="@+id/launch_secondary_activity_rtl_button"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:onClick="launchSecondaryActivity"
        android:tag="RIGHT_TO_LEFT"
        android:text="Launch Secondary Activity in RTL" />

    <Button
        android:id="@+id/launch_placeholder_split_button"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_centerHorizontal="true"
        android:onClick="launchPlaceholderSplit"
        android:tag="LEFT_TO_RIGHT"
        android:text="Launch Placeholder Split" />

    <Button
        android:id="@+id/launch_always_expand_activity_button"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_centerHorizontal="true"
        android:onClick="launchAlwaysExpandActivity"
        android:text="Launch Always Expand Activity" />

    <Button
        android:id="@+id/launch_placeholder_split_rtl_button"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:onClick="launchPlaceholderSplit"
        android:tag="RIGHT_TO_LEFT"
        android:text="Launch Placeholder Split in RTL" />

</LinearLayout>
+76 −46
Original line number Diff line number Diff line
@@ -16,22 +16,25 @@

package com.android.server.wm.flicker.testapp;


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.ArraySet;
import android.util.Log;
import android.view.View;

import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
import androidx.annotation.NonNull;
import androidx.window.embedding.ActivityFilter;
import androidx.window.embedding.ActivityRule;
import androidx.window.embedding.EmbeddingAspectRatio;
import androidx.window.embedding.RuleController;
import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
import androidx.window.extensions.embedding.EmbeddingRule;
import androidx.window.extensions.embedding.SplitPairRule;
import androidx.window.extensions.embedding.SplitPlaceholderRule;

import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
import androidx.window.embedding.SplitAttributes;
import androidx.window.embedding.SplitAttributes.LayoutDirection;
import androidx.window.embedding.SplitController;
import androidx.window.embedding.SplitPairFilter;
import androidx.window.embedding.SplitPairRule;
import androidx.window.embedding.SplitPlaceholderRule;
import androidx.window.embedding.SplitRule;

import java.util.HashSet;
import java.util.Set;
@@ -40,16 +43,27 @@ import java.util.Set;
public class ActivityEmbeddingMainActivity extends Activity {
    private static final String TAG = "ActivityEmbeddingMainActivity";
    private static final float DEFAULT_SPLIT_RATIO = 0.5f;
    private RuleController mRuleController;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_embedding_main_layout);
        final SplitController.SplitSupportStatus status = SplitController.getInstance(
                this).getSplitSupportStatus();
        if (status != SplitController.SplitSupportStatus.SPLIT_AVAILABLE) {
            throw new RuntimeException(
                    "Unable to initiate SplitController in ActivityEmbeddingMainActivity, "
                            + "splitSupportStatus = " + status);
        }
        mRuleController = RuleController.getInstance(this);
    }

    /** R.id.launch_secondary_activity_button onClick */
    public void launchSecondaryActivity(View view) {
        initializeSplitRules(createSplitPairRules());
        final String layoutDirection = view.getTag().toString();
        mRuleController.clearRules();
        mRuleController.addRule(createSplitPairRules(layoutDirection));
        startActivity(new Intent().setComponent(
                ActivityOptions.ActivityEmbedding.SecondaryActivity.COMPONENT));
    }
@@ -73,51 +87,67 @@ public class ActivityEmbeddingMainActivity extends Activity {

    /** R.id.launch_placeholder_split_button onClick */
    public void launchPlaceholderSplit(View view) {
        initializeSplitRules(createSplitPlaceholderRules());
        final String layoutDirection = view.getTag().toString();
        mRuleController.clearRules();
        mRuleController.addRule(createSplitPlaceholderRules(layoutDirection));
        startActivity(new Intent().setComponent(
                ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT));
    }

    private void initializeSplitRules(Set<EmbeddingRule> rules) {
        ActivityEmbeddingComponent embeddingComponent =
                ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
        if (embeddingComponent == null) {
            // Embedding not supported
            Log.d(TAG, "ActivityEmbedding is not supported on this device");
            finish();
            return;
        }
        embeddingComponent.setEmbeddingRules(rules);
    private static SplitPairRule createSplitPairRules(@NonNull String layoutDirection) {
        final Set<SplitPairFilter> pairFilters = new HashSet<>();
        final SplitPairFilter activitiesPair = new SplitPairFilter(
                ActivityOptions.ActivityEmbedding.MainActivity.COMPONENT,
                ActivityOptions.ActivityEmbedding.SecondaryActivity.COMPONENT,
                null /* secondaryActivityIntentAction */);
        pairFilters.add(activitiesPair);
        final SplitAttributes splitAttributes = new SplitAttributes.Builder()
                .setSplitType(SplitAttributes.SplitType.SPLIT_TYPE_EQUAL)
                .setLayoutDirection(parseLayoutDirection(layoutDirection))
                .build();
        // Setting thresholds to ALWAYS_ALLOW values to make it easy for running on all devices.
        final SplitPairRule rule = new SplitPairRule.Builder(pairFilters)
                .setDefaultSplitAttributes(splitAttributes)
                .setMinWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
                .setMinHeightDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
                .setMinSmallestWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
                .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ALWAYS_ALLOW)
                .setMaxAspectRatioInLandscape(EmbeddingAspectRatio.ALWAYS_ALLOW)
                .build();
        return rule;
    }

    private Set<EmbeddingRule> createSplitPairRules() {
        final Set<EmbeddingRule> rules = new ArraySet<>();
        final SplitPairRule rule = new SplitPairRule.Builder(
                activitiesPair -> activitiesPair.first instanceof ActivityEmbeddingMainActivity
                        && activitiesPair.second instanceof ActivityEmbeddingSecondaryActivity,
                activityIntentPair ->
                        activityIntentPair.first instanceof ActivityEmbeddingMainActivity
                                && activityIntentPair.second.getComponent().equals(ActivityOptions
                                .ActivityEmbedding.SecondaryActivity.COMPONENT),
                windowMetrics -> true)
                .setSplitRatio(DEFAULT_SPLIT_RATIO)
    private static SplitPlaceholderRule createSplitPlaceholderRules(
            @NonNull String layoutDirection) {
        final Set<ActivityFilter> activityFilters = new HashSet<>();
        activityFilters.add(new ActivityFilter(
                ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT,
                null /* intentAction */));
        final Intent intent = new Intent();
        intent.setComponent(
                ActivityOptions.ActivityEmbedding.PlaceholderSecondaryActivity.COMPONENT);
        final SplitAttributes splitAttributes = new SplitAttributes.Builder()
                .setSplitType(SplitAttributes.SplitType.SPLIT_TYPE_EQUAL)
                .setLayoutDirection(parseLayoutDirection(layoutDirection))
                .build();
        final SplitPlaceholderRule rule = new SplitPlaceholderRule.Builder(activityFilters, intent)
                .setDefaultSplitAttributes(splitAttributes)
                .setMinWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
                .setMinHeightDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
                .setMinSmallestWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
                .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ALWAYS_ALLOW)
                .setMaxAspectRatioInLandscape(EmbeddingAspectRatio.ALWAYS_ALLOW)
                .build();
        rules.add(rule);
        return rules;
        return rule;
    }

    private Set<EmbeddingRule> createSplitPlaceholderRules() {
        final Set<EmbeddingRule> rules = new ArraySet<>();
        final SplitPlaceholderRule rule = new SplitPlaceholderRule.Builder(
                new Intent().setComponent(
                        ActivityOptions.ActivityEmbedding.PlaceholderSecondaryActivity.COMPONENT),
                activity -> activity instanceof ActivityEmbeddingPlaceholderPrimaryActivity,
                intent -> intent.getComponent().equals(
                        ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT),
                windowMetrics -> true)
                .setSplitRatio(DEFAULT_SPLIT_RATIO)
                .build();
        rules.add(rule);
        return rules;
    private static LayoutDirection parseLayoutDirection(@NonNull String layoutDirectionStr) {
        if (layoutDirectionStr.equals(LayoutDirection.LEFT_TO_RIGHT.toString())) {
            return LayoutDirection.LEFT_TO_RIGHT;
        }
        if (layoutDirectionStr.equals(LayoutDirection.RIGHT_TO_LEFT.toString())) {
            return LayoutDirection.RIGHT_TO_LEFT;
        }
        return LayoutDirection.LOCALE;
    }
}