Add flicker test for ActivityEmbedding (1/n)

Add base and helper classes for ActivityEmbedding flicker tests.

Bug: 238043427
Test: atest FlickerTests:OpenActivityEmbeddingPlaceholderSplit
Change-Id: I60dae000fbb22e70aebea1f7c42ddce490c10bab
This commit is contained in:
Chris Li
2022-06-28 11:29:40 +08:00
parent 9475638a68
commit d498d2f451
15 changed files with 546 additions and 1 deletions

View File

@@ -46,6 +46,7 @@ android_test {
"launcher-helper-lib",
"launcher-aosp-tapl",
"platform-test-annotations",
"wm-flicker-window-extensions",
],
}
@@ -83,5 +84,21 @@ java_library {
"flickertestapplib",
"truth-prebuilt",
"app-helpers-core",
"wm-flicker-window-extensions",
],
}
android_library_import {
name: "wm-flicker-window-extensions_nodeps",
aars: ["libs/window-extensions-release.aar"],
sdk_version: "current",
}
java_library {
name: "wm-flicker-window-extensions",
sdk_version: "current",
static_libs: [
"wm-flicker-window-extensions_nodeps",
],
installable: false,
}

View File

@@ -43,6 +43,7 @@
<!-- Allow the test to write directly to /sdcard/ -->
<application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
<uses-library android:name="androidx.window.extensions" android:required="false"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"

Binary file not shown.

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2022 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.app.Instrumentation
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.Before
abstract class ActivityEmbeddingTestBase {
val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
val testApp = ActivityEmbeddingAppHelper(instrumentation)
@Before
fun assumeActivityEmbeddingSupported() {
// The test should only be run on devices that support ActivityEmbedding.
ActivityEmbeddingAppHelper.assumeActivityEmbeddingSupportedDevice()
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2022 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.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
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 opening an activity that will launch another activity as ActivityEmbedding placeholder in
* split.
*
* To run this test: `atest FlickerTests:OpenActivityEmbeddingPlaceholderSplit`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenActivityEmbeddingPlaceholderSplit(private val testSpec: FlickerTestParameter) :
ActivityEmbeddingTestBase() {
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
eachRun {
testApp.launchViaIntent(wmHelper)
}
}
transitions {
testApp.launchPlaceholderSplit(wmHelper)
}
teardown {
test {
device.pressHome()
testApp.exit(wmHelper)
}
}
}
}
@Presubmit
@Test
fun mainActivityBecomesInvisible() {
testSpec.assertLayers {
isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
.then()
.isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
}
}
@Presubmit
@Test
fun placeholderSplitBecomesVisible() {
testSpec.assertLayers {
isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
.then()
.isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
}
testSpec.assertLayers {
isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
.then()
.isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
}
}
companion object {
/**
* Creates the test configurations.
*
* See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
* repetitions, screen orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
repetitions = 1,
supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
)
)
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2022 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.helpers
import android.app.Instrumentation
import android.support.test.launcherhelper.ILauncherStrategy
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.util.Log
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import androidx.window.extensions.WindowExtensions
import androidx.window.extensions.WindowExtensionsProvider
import androidx.window.extensions.embedding.ActivityEmbeddingComponent
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.traces.common.FlickerComponentName
import com.android.server.wm.traces.common.windowmanager.WindowManagerState.Companion.STATE_RESUMED
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.Assume.assumeNotNull
class ActivityEmbeddingAppHelper @JvmOverloads constructor(
instr: Instrumentation,
launcherName: String = ActivityOptions.ACTIVITY_EMBEDDING_LAUNCHER_NAME,
component: FlickerComponentName = MAIN_ACTIVITY_COMPONENT,
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
.getInstance(instr)
.launcherStrategy
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
/**
* Clicks the button to launch the placeholder primary activity, which should launch the
* placeholder secondary activity based on the placeholder rule.
*/
fun launchPlaceholderSplit(wmHelper: WindowManagerStateHelper) {
val launchButton = uiDevice.wait(
Until.findObject(By.res(getPackage(), "launch_placeholder_split_button")),
FIND_TIMEOUT)
require(launchButton != null) {
"Can't find launch placeholder split button on screen."
}
launchButton.click()
wmHelper.StateSyncBuilder()
.withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, STATE_RESUMED)
.withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, STATE_RESUMED)
.waitForAndVerify()
}
companion object {
private const val TAG = "ActivityEmbeddingAppHelper"
val MAIN_ACTIVITY_COMPONENT = ActivityOptions
.ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
val PLACEHOLDER_PRIMARY_COMPONENT = ActivityOptions
.ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
val PLACEHOLDER_SECONDARY_COMPONENT = ActivityOptions
.ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME
.toFlickerComponent()
@JvmStatic
fun getWindowExtensions(): WindowExtensions? {
try {
return WindowExtensionsProvider.getWindowExtensions()
} catch (e: NoClassDefFoundError) {
Log.d(TAG, "Extension implementation not found")
} catch (e: UnsupportedOperationException) {
Log.d(TAG, "Stub Extension")
}
return null
}
@JvmStatic
fun getActivityEmbeddingComponent(): ActivityEmbeddingComponent? {
return getWindowExtensions()?.activityEmbeddingComponent
}
@JvmStatic
fun assumeActivityEmbeddingSupportedDevice() {
assumeNotNull(getActivityEmbeddingComponent())
}
}
}

View File

@@ -26,6 +26,11 @@ android_test {
srcs: ["**/*.java"],
sdk_version: "current",
test_suites: ["device-tests"],
static_libs: [
"androidx.test.ext.junit",
"wm-flicker-common-app-helpers",
"wm-flicker-window-extensions",
],
}
java_library {

View File

@@ -15,12 +15,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.wm.flicker.testapp">
package="com.android.server.wm.flicker.testapp">
<uses-sdk android:minSdkVersion="29"
android:targetSdkVersion="29"/>
<application android:allowBackup="false"
android:supportsRtl="true">
<uses-library android:name="androidx.window.extensions" android:required="false"/>
<activity android:name=".SimpleActivity"
android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
android:theme="@style/CutoutShortEdges"
@@ -163,5 +165,33 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ActivityEmbeddingMainActivity"
android:label="ActivityEmbedding Main"
android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
android:theme="@style/CutoutShortEdges"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ActivityEmbeddingPlaceholderPrimaryActivity"
android:label="ActivityEmbedding Placeholder Primary"
android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
android:theme="@style/CutoutShortEdges"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="false">
</activity>
<activity
android:name=".ActivityEmbeddingPlaceholderSecondaryActivity"
android:label="ActivityEmbedding Placeholder Secondary"
android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
android:theme="@style/CutoutShortEdges"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="false"/>
</application>
</manifest>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_activity_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/holo_orange_light">
<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:text="Launch Placeholder Split" />
</LinearLayout>

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2022 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.testapp;
import android.app.Activity;
import android.os.Bundle;
/** Base activity of ActivityEmbedding split activities. */
public abstract class ActivityEmbeddingBaseActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_embedding_base_layout);
findViewById(R.id.root_activity_layout).setBackgroundColor(getBackgroundColor());
}
/** Sets different colors to visually distinguish split pairs. */
abstract int getBackgroundColor();
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2022 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.testapp;
import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME;
import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME;
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 androidx.window.extensions.embedding.ActivityEmbeddingComponent;
import androidx.window.extensions.embedding.EmbeddingRule;
import androidx.window.extensions.embedding.SplitPlaceholderRule;
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
import java.util.Set;
/** Main activity of the ActivityEmbedding test app to launch other embedding activities. */
public class ActivityEmbeddingMainActivity extends Activity {
private static final String TAG = "ActivityEmbeddingMainActivity";
private static final float DEFAULT_SPLIT_RATIO = 0.5f;
private ActivityEmbeddingComponent mEmbeddingComponent;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_embedding_main_layout);
initializeSplitRules();
}
/** R.id.launch_placeholder_split_button onClick */
public void launchPlaceholderSplit(View view) {
startActivity(new Intent().setComponent(
ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME));
}
private void initializeSplitRules() {
mEmbeddingComponent = ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
if (mEmbeddingComponent == null) {
// Embedding not supported
Log.d(TAG, "ActivityEmbedding is not supported on this device");
finish();
return;
}
mEmbeddingComponent.setEmbeddingRules(getSplitRules());
}
private Set<EmbeddingRule> getSplitRules() {
final Set<EmbeddingRule> rules = new ArraySet<>();
final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule.Builder(
new Intent().setComponent(
ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME),
activity -> activity instanceof ActivityEmbeddingPlaceholderPrimaryActivity,
intent -> intent.getComponent().equals(
ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME),
windowMetrics -> true)
.setSplitRatio(DEFAULT_SPLIT_RATIO)
.build();
rules.add(placeholderRule);
return rules;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2022 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.testapp;
import android.graphics.Color;
/**
* Primary activity that will launch {@link ActivityEmbeddingPlaceholderSecondaryActivity} to split
* as placeholder based on the placeholder rule.
*/
public class ActivityEmbeddingPlaceholderPrimaryActivity extends ActivityEmbeddingBaseActivity {
@Override
int getBackgroundColor() {
return Color.BLUE;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2022 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.testapp;
import android.graphics.Color;
/**
* Activity to be used as the secondary placeholder activity to split with
* {@link ActivityEmbeddingPlaceholderPrimaryActivity}.
*/
public class ActivityEmbeddingPlaceholderSecondaryActivity extends ActivityEmbeddingBaseActivity {
@Override
int getBackgroundColor() {
return Color.GREEN;
}
}

View File

@@ -87,4 +87,17 @@ public class ActivityOptions {
public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".NotificationActivity");
public static final String ACTIVITY_EMBEDDING_LAUNCHER_NAME = "ActivityEmbeddingMainActivity";
public static final ComponentName ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ActivityEmbeddingMainActivity");
public static final ComponentName
ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderPrimaryActivity");
public static final ComponentName
ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
}