Adding MediaProjection Functional Flicker Test Scenarios
Adding Flicker tests for:
* Launching a new app with PSS
* Launching a recent app with PSS
* Launching a new app from split screen with PSS
* Launching a recent app from split screen with PSS
* Launching a new app that is part of a split pair in PSS
* Launching a recent app that is part of a split pair in PSS
* Launching a new app with PSS with an extra intent before opening the PSS app
Bug: 302676546
Bug: 327635591
Bug: 299422238
Test: added tests
Flag: TEST_ONLY
Change-Id: I3be1a79e085cf1ec26929a4fd6cd315bdcc3fd24
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
deleted file mode 100644
index 85e6a8d..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright (C) 2020 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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
- name: "WMShellFlickerTestsMediaProjection",
- defaults: ["WMShellFlickerTestsDefault"],
- manifest: "AndroidManifest.xml",
- test_config_template: "AndroidTestTemplate.xml",
- srcs: ["src/**/*.kt"],
- static_libs: [
- "WMShellFlickerTestsBase",
- "WMShellScenariosMediaProjection",
- "WMShellTestUtils",
- ],
- data: ["trace_config/*"],
-}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
deleted file mode 100644
index 74b0daf..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.wm.shell.flicker">
-
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
- <!-- Read and write traces from external storage -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <!-- Allow the test to write directly to /sdcard/ -->
- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
- <!-- Write secure settings -->
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <!-- Capture screen contents -->
- <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
- <!-- Enable / Disable tracing !-->
- <uses-permission android:name="android.permission.DUMP" />
- <!-- Run layers trace -->
- <uses-permission android:name="android.permission.HARDWARE_TEST"/>
- <!-- Capture screen recording -->
- <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
- <!-- Workaround grant runtime permission exception from b/152733071 -->
- <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
- <uses-permission android:name="android.permission.READ_LOGS"/>
- <!-- Force-stop test apps -->
- <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
- <!-- Control test app's media session -->
- <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
- <!-- ATM.removeRootTasksWithActivityTypes() -->
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
- <!-- Enable bubble notification-->
- <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
- <!-- Allow the test to connect to perfetto trace processor -->
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
- <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
-
- <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
- <application android:requestLegacyExternalStorage="true"
- android:networkSecurityConfig="@xml/network_security_config"
- android:largeHeap="true">
- <uses-library android:name="android.test.runner"/>
-
- <service android:name=".NotificationListener"
- android:exported="true"
- android:label="WMShellTestsNotificationListenerService"
- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
- <intent-filter>
- <action android:name="android.service.notification.NotificationListenerService" />
- </intent-filter>
- </service>
-
- <service android:name="com.android.wm.shell.flicker.utils.MediaProjectionService"
- android:foregroundServiceType="mediaProjection"
- android:label="WMShellTestsMediaProjectionService"
- android:enabled="true">
- </service>
-
- <!-- (b/197936012) Remove startup provider due to test timeout issue -->
- <provider
- android:name="androidx.startup.InitializationProvider"
- android:authorities="${applicationId}.androidx-startup"
- tools:node="remove" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.wm.shell.flicker"
- android:label="WindowManager Shell Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
deleted file mode 100644
index 40dbbac..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}">
- <option name="test-tag" value="FlickerTests"/>
- <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
- <option name="isolated-storage" value="false"/>
-
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <!-- disable DeprecatedTargetSdk warning -->
- <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
- <!-- keeps the screen on during tests -->
- <option name="screen-always-on" value="on"/>
- <!-- prevents the phone from restarting -->
- <option name="force-skip-system-props" value="true"/>
- <!-- set WM tracing verbose level to all -->
- <option name="run-command" value="cmd window tracing level all"/>
- <!-- set WM tracing to frame (avoid incomplete states) -->
- <option name="run-command" value="cmd window tracing frame"/>
- <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
- <option name="run-command" value="pm disable com.google.android.internal.betterbug"/>
- <!-- ensure lock screen mode is swipe -->
- <option name="run-command" value="locksettings set-disabled false"/>
- <!-- restart launcher to activate TAPL -->
- <option name="run-command"
- value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/>
- <!-- Increase trace size: 20mb for WM and 80mb for SF -->
- <option name="run-command" value="cmd window tracing size 20480"/>
- <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/>
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="test-user-token" value="%TEST_USER%"/>
- <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
- <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
- <option name="run-command" value="settings put system show_touches 1"/>
- <option name="run-command" value="settings put system pointer_location 1"/>
- <option name="teardown-command"
- value="settings delete secure show_ime_with_hard_keyboard"/>
- <option name="teardown-command" value="settings delete system show_touches"/>
- <option name="teardown-command" value="settings delete system pointer_location"/>
- <option name="teardown-command"
- value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/>
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="{MODULE}.apk"/>
- <option name="test-file-name" value="FlickerTestApp.apk"/>
- </target_preparer>
-
- <!-- Needed for pushing the trace config file -->
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="push-file"
- key="trace_config.textproto"
- value="/data/misc/perfetto-traces/trace_config.textproto"
- />
- <!--Install the content provider automatically when we push some file in sdcard folder.-->
- <!--Needed to avoid the installation during the test suite.-->
- <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/>
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="{PACKAGE}"/>
- <option name="shell-timeout" value="6600s"/>
- <option name="test-timeout" value="6000s"/>
- <option name="hidden-api-checks" value="false"/>
- <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
- <!-- PerfettoListener related arguments -->
- <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
- <option name="instrumentation-arg"
- key="perfetto_config_file"
- value="trace_config.textproto"
- />
- <option name="instrumentation-arg" key="per_run" value="true"/>
- <option name="instrumentation-arg" key="perfetto_persist_pid_track" value="true"/>
- </test>
- <!-- Needed for pulling the collected trace config on to the host -->
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="pull-pattern-keys" value="perfetto_file_path"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.wm.shell.flicker/files"/>
- <option name="collect-on-run-ended-only" value="true"/>
- <option name="clean-up" value="true"/>
- </metrics_collector>
-</configuration>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml
deleted file mode 100644
index 4bd9ca0..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<network-security-config>
- <domain-config cleartextTrafficPermitted="true">
- <domain includeSubdomains="true">localhost</domain>
- </domain-config>
-</network-security-config>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
deleted file mode 100644
index 9f2e497..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
+++ /dev/null
@@ -1,71 +0,0 @@
-# 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.
-
-# proto-message: TraceConfig
-
-# Enable periodic flushing of the trace buffer into the output file.
-write_into_file: true
-
-# Writes the userspace buffer into the file every 1s.
-file_write_period_ms: 2500
-
-# See b/126487238 - we need to guarantee ordering of events.
-flush_period_ms: 30000
-
-# The trace buffers needs to be big enough to hold |file_write_period_ms| of
-# trace data. The trace buffer sizing depends on the number of trace categories
-# enabled and the device activity.
-
-# RSS events
-buffers: {
- size_kb: 63488
- fill_policy: RING_BUFFER
-}
-
-data_sources {
- config {
- name: "linux.process_stats"
- target_buffer: 0
- # polled per-process memory counters and process/thread names.
- # If you don't want the polled counters, remove the "process_stats_config"
- # section, but keep the data source itself as it still provides on-demand
- # thread/process naming for ftrace data below.
- process_stats_config {
- scan_all_processes_on_start: true
- }
- }
-}
-
-data_sources: {
- config {
- name: "linux.ftrace"
- ftrace_config {
- ftrace_events: "ftrace/print"
- ftrace_events: "task/task_newtask"
- ftrace_events: "task/task_rename"
- atrace_categories: "ss"
- atrace_categories: "wm"
- atrace_categories: "am"
- atrace_categories: "aidl"
- atrace_categories: "input"
- atrace_categories: "binder_driver"
- atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker.testapp"
- atrace_apps: "com.android.systemui"
- atrace_apps: "com.android.wm.shell.flicker.service"
- atrace_apps: "com.google.android.apps.nexuslauncher"
- }
- }
-}
-
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt
new file mode 100644
index 0000000..2b9772d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionFromSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionFromSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionFromSplitScreenTest() : StartAppMediaProjectionFromSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt
new file mode 100644
index 0000000..e92297b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionInSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionInSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionInSplitScreenTest() : StartAppMediaProjectionInSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt
new file mode 100644
index 0000000..3f810759
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjection
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjection]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionTest() : StartAppMediaProjection()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt
new file mode 100644
index 0000000..1975cc7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionWithExtraIntent
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionWithExtraIntent]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionWithExtraIntentTest : StartAppMediaProjectionWithExtraIntent()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt
new file mode 100644
index 0000000..943033c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjectionFromSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjectionFromSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionFromSplitScreenTest() : StartRecentAppMediaProjectionFromSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt
new file mode 100644
index 0000000..6facfd5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjectionInSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjectionInSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionInSplitScreenTest() : StartRecentAppMediaProjectionInSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt
new file mode 100644
index 0000000..bab0905
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjection
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjection]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionTest() : StartRecentAppMediaProjection()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt
new file mode 100644
index 0000000..fe2c578
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session.
+ *
+ * This is for testing that the requested app is opened as expected upon selecting it from the app
+ * selector, so capture can proceed as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjection {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt
new file mode 100644
index 0000000..3beece8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session, while the HOST app is in
+ * split screen
+ *
+ * This is for testing that the requested app is opened as expected upon selecting it from the app
+ * selector, so capture can proceed as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionFromSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val simpleApp = SimpleAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, simpleApp, testApp, initialRotation)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, simpleApp, testApp)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt
new file mode 100644
index 0000000..d3186ae
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session, while the TARGET app is in
+ * split screen (next to the host app)
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionInSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, targetApp, testApp, initialRotation)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .withWindowSurfaceAppeared(testApp)
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ targetApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt
new file mode 100644
index 0000000..0b2a1ca
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session but launches an intent to
+ * return to the home screen, before the intent for opening the requested app to capture.
+ *
+ * This is for testing that even if a different intent interrupts the process the launching the
+ * requested capture target, the MediaProjection process isn't interrupted and the device is still
+ * interactive.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionWithExtraIntent {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjectionWithExtraIntent(wmHelper, targetApp)
+
+ // Check we can still interact with device after
+ tapl.workspace.switchToAllApps().getAppIcon(targetApp.appName).launch(targetApp.packageName)
+
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt
new file mode 100644
index 0000000..30e0e4a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents.
+ *
+ * This is for testing that the app is started from recents and capture proceeds as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjection {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ targetApp.open()
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt
new file mode 100644
index 0000000..f1dcf1f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents while the HOST
+ * app is in split screen.
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjectionFromSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val simpleApp = SimpleAppHelper(instrumentation)
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ targetApp.open()
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, simpleApp, testApp, initialRotation)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ // The app we want to open for PSS will be the second item in the carousel,
+ // because the first will be the app open in split screen alongside the MediaProjection app
+ testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp, recentTasksIndex = 1)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt
new file mode 100644
index 0000000..0a6992f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents while the
+ * TARGET app is in split screen (with host app).
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjectionInSplitScreen {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.workspace.switchToOverview().dismissAllTasks()
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, targetApp, testApp, initialRotation)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp)
+
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .withWindowSurfaceAppeared(testApp)
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ targetApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
index f9706969..8c2bdad 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
@@ -17,7 +17,11 @@
package com.android.wm.shell.flicker.utils
object MediaProjectionUtils {
- const val REQUEST_CODE: Int = 99
+ // Request code for the normal media projection request
+ const val REQUEST_CODE_NORMAL: Int = 11
+ // Request code for the media projection request which will include an extra intent to open
+ // home screen before starting requested app
+ const val REQUEST_CODE_EXTRA_INTENT: Int = 12
const val MSG_START_FOREGROUND_DONE: Int = 1
const val MSG_SERVICE_DESTROYED: Int = 2
const val EXTRA_MESSENGER: String = "messenger"
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
index 69fde01..9e48848 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
@@ -65,10 +65,45 @@
.waitForAndVerify()
}
+ fun startSingleAppMediaProjectionWithExtraIntent(
+ wmHelper: WindowManagerStateHelper,
+ targetApp: StandardAppHelper
+ ) {
+ clickStartMediaProjectionWithExtraIntentButton()
+ chooseSingleAppOption()
+ startScreenSharing()
+ selectTargetApp(targetApp.appName)
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
+ }
+
+ fun startSingleAppMediaProjectionFromRecents(
+ wmHelper: WindowManagerStateHelper,
+ targetApp: StandardAppHelper,
+ recentTasksIndex: Int = 0,
+ ) {
+ clickStartMediaProjectionButton()
+ chooseSingleAppOption()
+ startScreenSharing()
+ selectTargetAppRecent(recentTasksIndex)
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .waitForAndVerify()
+ }
+
private fun clickStartMediaProjectionButton() {
findObject(By.res(packageName, START_MEDIA_PROJECTION_BUTTON_ID)).also { it.click() }
}
+ private fun clickStartMediaProjectionWithExtraIntentButton() {
+ findObject(By.res(packageName, START_MEDIA_PROJECTION_NEW_INTENT_BUTTON_ID)).also { it.click() }
+ }
+
private fun chooseEntireScreenOption() {
findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
@@ -92,6 +127,13 @@
findObject(By.text(targetAppName)).also { it.click() }
}
+ private fun selectTargetAppRecent(recentTasksIndex: Int) {
+ // Scroll to to find target app to launch then click app icon it to start capture
+ val recentsTasksRecycler =
+ findObject(By.res(SYSTEMUI_PACKAGE, MEDIA_PROJECTION_RECENT_TASKS))
+ recentsTasksRecycler.children[recentTasksIndex].also{ it.click() }
+ }
+
private fun chooseSingleAppOption() {
findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
@@ -116,8 +158,10 @@
const val TIMEOUT: Long = 5000L
const val ACCEPT_RESOURCE_ID: String = "android:id/button1"
const val START_MEDIA_PROJECTION_BUTTON_ID: String = "button_start_mp"
+ const val START_MEDIA_PROJECTION_NEW_INTENT_BUTTON_ID: String = "button_start_mp_new_intent"
val SCREEN_SHARE_OPTIONS_PATTERN: Pattern =
Pattern.compile("$SYSTEMUI_PACKAGE:id/screen_share_mode_(options|spinner)")
+ const val MEDIA_PROJECTION_RECENT_TASKS: String = "media_projection_recent_tasks_recycler"
const val ENTIRE_SCREEN_STRING_RES_NAME: String =
"screen_share_permission_dialog_option_entire_screen"
const val SINGLE_APP_STRING_RES_NAME: String =
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
index 46f01e6..c34d200 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
@@ -16,17 +16,27 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
android:orientation="vertical"
android:background="@android:color/holo_orange_light">
<Button
android:id="@+id/button_start_mp"
- android:layout_width="500dp"
- android:layout_height="500dp"
+ android:layout_margin="16dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="Start Media Projection"
android:textAppearance="?android:attr/textAppearanceLarge"/>
+ <Button
+ android:id="@+id/button_start_mp_new_intent"
+ android:layout_margin="16dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="Start Media Projection with extra intent"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
index a24a482..b29b874 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
@@ -19,7 +19,8 @@
import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.EXTRA_MESSENGER;
import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_SERVICE_DESTROYED;
import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_START_FOREGROUND_DONE;
-import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE_NORMAL;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE_EXTRA_INTENT;
import android.app.Activity;
import android.content.ComponentName;
@@ -71,13 +72,17 @@
setContentView(R.layout.activity_start_media_projection);
Button startMediaProjectionButton = findViewById(R.id.button_start_mp);
+ Button startMediaProjectionButton2 = findViewById(R.id.button_start_mp_new_intent);
startMediaProjectionButton.setOnClickListener(v ->
- startActivityForResult(mService.createScreenCaptureIntent(), REQUEST_CODE));
+ startActivityForResult(mService.createScreenCaptureIntent(), REQUEST_CODE_NORMAL));
+ startMediaProjectionButton2.setOnClickListener(v ->
+ startActivityForResult(mService.createScreenCaptureIntent(),
+ REQUEST_CODE_EXTRA_INTENT));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode != REQUEST_CODE) {
+ if (requestCode != REQUEST_CODE_NORMAL && requestCode != REQUEST_CODE_EXTRA_INTENT) {
throw new IllegalStateException("Unknown request code: " + requestCode);
}
if (resultCode != RESULT_OK) {
@@ -85,6 +90,11 @@
}
Log.d(TAG, "onActivityResult");
startMediaProjectionService(resultCode, data);
+ if (requestCode == REQUEST_CODE_EXTRA_INTENT) {
+ Intent startMain = new Intent(Intent.ACTION_MAIN);
+ startMain.addCategory(Intent.CATEGORY_HOME);
+ startActivity(startMain);
+ }
}
private void startMediaProjectionService(int resultCode, Intent resultData) {
@@ -122,7 +132,7 @@
displayBounds.width(), displayBounds.height(), PixelFormat.RGBA_8888, 1);
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
- "DanielDisplay",
+ "TestDisplay",
displayBounds.width(),
displayBounds.height(),
DisplayMetrics.DENSITY_HIGH,