1/ Add test apps from WM shell package into flicker
Add both apps to the same package to unify all test apps and helpers into a single reusable place
Test: atest FlickerLibTest && atest FlickerTests
Change-Id: I9fa18eb31b50c4e6869352250be0c89a9acb0be8
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 725963b..6e935d1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -15,41 +15,41 @@
-->
<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"/>
+ android:targetSdkVersion="29"/>
<application android:allowBackup="false"
- android:supportsRtl="true">
+ 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"
- android:label="SimpleApp"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:label="SimpleActivity"
+ 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=".ImeActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity"
- android:theme="@style/CutoutShortEdges"
- android:label="ImeApp"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:label="ImeActivity"
+ 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=".ImeActivityAutoFocus"
- android:theme="@style/CutoutShortEdges"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
- android:windowSoftInputMode="stateVisible"
- android:configChanges="orientation|screenSize"
- android:label="ImeAppAutoFocus"
- android:exported="true">
+ android:theme="@style/CutoutShortEdges"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
+ android:windowSoftInputMode="stateVisible"
+ android:configChanges="orientation|screenSize"
+ android:label="ImeAppAutoFocus"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -66,34 +66,34 @@
</intent-filter>
</activity>
<activity android:name=".SeamlessRotationActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
- android:theme="@style/CutoutShortEdges"
- android:configChanges="orientation|screenSize"
- android:label="SeamlessApp"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize"
+ android:label="SeamlessActivity"
+ 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=".NonResizeableActivity"
- android:theme="@style/CutoutShortEdges"
- android:resizeableActivity="false"
- android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity"
- android:label="NonResizeableApp"
- android:exported="true"
- android:showOnLockScreen="true">
+ android:theme="@style/CutoutShortEdges"
+ android:resizeableActivity="false"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity"
+ android:label="NonResizeableActivity"
+ android:exported="true"
+ android:showOnLockScreen="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name=".ButtonActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ButtonActivity"
- android:theme="@style/CutoutShortEdges"
- android:configChanges="orientation|screenSize"
- android:label="ButtonActivity"
- android:exported="true">
+ <activity android:name=".LaunchNewActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize"
+ android:label="LaunchNewActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -111,55 +111,56 @@
</intent-filter>
</activity>
<activity android:name=".DialogThemedActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.DialogThemedActivity"
- android:configChanges="orientation|screenSize"
- android:theme="@style/DialogTheme"
- android:label="DialogThemedActivity"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.DialogThemedActivity"
+ android:configChanges="orientation|screenSize"
+ android:theme="@style/DialogTheme"
+ android:label="DialogThemedActivity"
+ 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=".PortraitOnlyActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitOnlyActivity"
- android:theme="@style/CutoutShortEdges"
- android:screenOrientation="portrait"
- android:configChanges="orientation|screenSize"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitOnlyActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:screenOrientation="portrait"
+ android:configChanges="orientation|screenSize"
+ 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=".ImeEditorPopupDialogActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ImeEditorPopupDialogActivity"
- android:configChanges="orientation|screenSize"
- android:theme="@style/CutoutShortEdges"
- android:label="ImeEditorPopupDialogActivity"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ImeEditorPopupDialogActivity"
+ android:configChanges="orientation|screenSize"
+ android:theme="@style/CutoutShortEdges"
+ android:label="ImeEditorPopupDialogActivity"
+ 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=".ShowWhenLockedActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ShowWhenLockedActivity"
- android:theme="@style/CutoutShortEdges"
- android:configChanges="orientation|screenSize"
- android:label="ShowWhenLockedActivity"
- android:showWhenLocked="true"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ShowWhenLockedActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize"
+ android:label="ShowWhenLockedActivity"
+ android:showWhenLocked="true"
+ 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=".NotificationActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.NotificationActivity"
- android:theme="@style/CutoutShortEdges"
- android:configChanges="orientation|screenSize"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.NotificationActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize"
+ android:label="NotificationActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -173,8 +174,8 @@
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" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
@@ -193,42 +194,110 @@
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="false"/>
<activity android:name=".MailActivity"
- android:exported="true"
- android:label="MailApp"
- android:taskAffinity="com.android.server.wm.flicker.testapp.MailActivity"
- android:theme="@style/Theme.AppCompat.Light">
+ android:exported="true"
+ android:label="MailActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.MailActivity"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".GameActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.GameActivity"
- android:immersive="true"
- android:theme="@android:style/Theme.NoTitleBar"
- android:configChanges="screenSize"
- android:label="GameApp"
- android:exported="true">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.GameActivity"
+ android:immersive="true"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:configChanges="screenSize"
+ android:label="GameActivity"
+ 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=".PipActivity"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.PipActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:launchMode="singleTop"
+ android:label="PipActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity android:name=".SplitScreenActivity"
+ android:resizeableActivity="true"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:label="SplitScreenPrimaryActivity"
+ 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=".SplitScreenSecondaryActivity"
+ android:resizeableActivity="true"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenSecondaryActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:label="SplitScreenSecondaryActivity"
+ 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=".SendNotificationActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SendNotificationActivity"
+ android:theme="@style/CutoutShortEdges"
+ android:label="SendNotificationActivity"
+ 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=".LaunchBubbleActivity"
+ android:label="LaunchBubbleActivity"
+ android:exported="true"
+ android:theme="@style/CutoutShortEdges"
+ android:launchMode="singleTop">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".BubbleActivity"
+ android:label="BubbleActivity"
+ android:exported="false"
+ android:theme="@style/CutoutShortEdges"
+ android:resizeableActivity="true"/>
<service
android:name=".AssistantInteractionSessionService"
android:exported="true"
- android:permission="android.permission.BIND_VOICE_INTERACTION" />
+ android:permission="android.permission.BIND_VOICE_INTERACTION"/>
<service
android:name=".AssistantRecognitionService"
android:exported="true"
android:label="Test Voice Interaction Service">
<intent-filter>
- <action android:name="android.speech.RecognitionService" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.speech.RecognitionService"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<meta-data
android:name="android.speech"
- android:resource="@xml/recognition_service" />
+ android:resource="@xml/recognition_service"/>
</service>
<service
android:name=".AssistantInteractionService"
@@ -236,12 +305,12 @@
android:label="Test Voice Interaction Service"
android:permission="android.permission.BIND_VOICE_INTERACTION">
<intent-filter>
- <action android:name="android.service.voice.VoiceInteractionService" />
+ <action android:name="android.service.voice.VoiceInteractionService"/>
</intent-filter>
<meta-data
android:name="android.voice_interaction"
- android:resource="@xml/interaction_service" />
+ android:resource="@xml/interaction_service"/>
</service>
</application>
- <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
+ <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/drawable/bg.png b/tests/FlickerTests/test-apps/flickerapp/res/drawable/bg.png
new file mode 100644
index 0000000..d424a17
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/drawable/bg.png
Binary files differ
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/drawable/ic_bubble.xml b/tests/FlickerTests/test-apps/flickerapp/res/drawable/ic_bubble.xml
new file mode 100644
index 0000000..4ea156d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/drawable/ic_bubble.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7.2,14.4m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M14.8,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15.2,8.8m-4.8,0a4.8,4.8 0,1 1,9.6 0a4.8,4.8 0,1 1,-9.6 0"/>
+</vector>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/drawable/ic_message.xml b/tests/FlickerTests/test-apps/flickerapp/res/drawable/ic_message.xml
new file mode 100644
index 0000000..45ed98c
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/drawable/ic_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M12,4c-4.97,0 -9,3.58 -9,8c0,1.53 0.49,2.97 1.33,4.18c0.12,0.18 0.2,0.46 0.1,0.66c-0.33,0.68 -0.79,1.52 -1.38,2.39c-0.12,0.17 0.01,0.41 0.21,0.39c0.63,-0.05 1.86,-0.26 3.38,-0.91c0.17,-0.07 0.36,-0.06 0.52,0.03C8.55,19.54 10.21,20 12,20c4.97,0 9,-3.58 9,-8S16.97,4 12,4zM16.94,11.63l-3.29,3.29c-0.13,0.13 -0.34,0.04 -0.34,-0.14v-1.57c0,-0.11 -0.1,-0.21 -0.21,-0.2c-2.19,0.06 -3.65,0.65 -5.14,1.95c-0.15,0.13 -0.38,0 -0.33,-0.19c0.7,-2.57 2.9,-4.57 5.5,-4.75c0.1,-0.01 0.18,-0.09 0.18,-0.19V8.2c0,-0.18 0.22,-0.27 0.34,-0.14l3.29,3.29C17.02,11.43 17.02,11.55 16.94,11.63z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
new file mode 100644
index 0000000..7c7b2ca
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <Button
+ android:id="@+id/button_finish"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginStart="8dp"
+ android:text="Finish" />
+ <Button
+ android:id="@+id/button_new_task"
+ android:layout_width="wrap_content"
+ android:layout_height="46dp"
+ android:layout_marginStart="8dp"
+ android:text="New Task" />
+ <Button
+ android:id="@+id/button_new_bubble"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:text="New Bubble" />
+
+ <Button
+ android:id="@+id/button_activity_for_result"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:text="Activity For Result" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
similarity index 100%
rename from tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml
rename to tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_main.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_main.xml
new file mode 100644
index 0000000..553c7fe0
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_main.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<RelativeLayout 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/black">
+
+ <Button
+ android:id="@+id/button_create"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="Add Bubble" />
+
+ <Button
+ android:id="@+id/button_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/button_create"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dp"
+ android:text="Cancel Bubble" />
+
+ <Button
+ android:id="@+id/button_cancel_all"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/button_cancel"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dp"
+ android:text="Cancel All Bubble" />
+</RelativeLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_notification.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_notification.xml
new file mode 100644
index 0000000..7c11984
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_notification.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<RelativeLayout 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/black">
+
+ <Button
+ android:id="@+id/button_send_notification"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="Send Notification" />
+</RelativeLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
new file mode 100644
index 0000000..f7ba45b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<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_blue_bright">
+
+ <!-- All the buttons (and other clickable elements) should be arranged in a way so that it is
+ possible to "cycle" over all them by clicking on the D-Pad DOWN button. The way we do it
+ here is by arranging them this vertical LL and by relying on the nextFocusDown attribute
+ where things are arranged differently and to circle back up to the top once we reach the
+ bottom. -->
+
+ <Button
+ android:id="@+id/enter_pip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Enter PIP"
+ android:onClick="enterPip"/>
+
+ <CheckBox
+ android:id="@+id/with_custom_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="With custom actions"/>
+
+ <RadioGroup
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:checkedButton="@id/enter_pip_on_leave_disabled">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Enter PiP on home press"/>
+
+ <RadioButton
+ android:id="@+id/enter_pip_on_leave_disabled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disabled"
+ android:onClick="onAutoPipSelected"/>
+
+ <RadioButton
+ android:id="@+id/enter_pip_on_leave_manual"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Via code behind"
+ android:onClick="onAutoPipSelected"/>
+
+ <RadioButton
+ android:id="@+id/enter_pip_on_leave_autoenter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Auto-enter PiP"
+ android:onClick="onAutoPipSelected"/>
+ </RadioGroup>
+
+ <RadioGroup
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:checkedButton="@id/ratio_default">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Ratio"/>
+
+ <RadioButton
+ android:id="@+id/ratio_default"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Default"
+ android:onClick="onRatioSelected"/>
+
+ <RadioButton
+ android:id="@+id/ratio_square"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Square [1:1]"
+ android:onClick="onRatioSelected"/>
+
+ <RadioButton
+ android:id="@+id/ratio_wide"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Wide [2:1]"
+ android:onClick="onRatioSelected"/>
+
+ <RadioButton
+ android:id="@+id/ratio_tall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Tall [1:2]"
+ android:onClick="onRatioSelected"/>
+ </RadioGroup>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Media Session"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:id="@+id/media_session_start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:nextFocusDown="@id/media_session_stop"
+ android:text="Start"/>
+
+ <Button
+ android:id="@+id/media_session_stop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:nextFocusDown="@id/enter_pip"
+ android:text="Stop"/>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
new file mode 100644
index 0000000..79e88e4
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<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_green_light">
+
+ <TextView
+ android:id="@+id/SplitScreenTest"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center_vertical|center_horizontal"
+ android:textIsSelectable="true"
+ android:text="PrimaryActivity"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
new file mode 100644
index 0000000..ed9feaf
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<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_blue_light">
+
+ <TextView
+ android:id="@+id/SplitScreenTest"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="SecondaryActivity"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
index 166e3ca..04a590d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
@@ -16,9 +16,6 @@
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;
@@ -39,8 +36,6 @@
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);
@@ -51,20 +46,24 @@
/** R.id.launch_placeholder_split_button onClick */
public void launchPlaceholderSplit(View view) {
- startActivity(new Intent().setComponent(
- ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME));
+ startActivity(
+ new Intent().setComponent(
+ ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT
+ )
+ );
}
private void initializeSplitRules() {
- mEmbeddingComponent = ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
- if (mEmbeddingComponent == null) {
+ ActivityEmbeddingComponent embeddingComponent =
+ ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
+ if (embeddingComponent == null) {
// Embedding not supported
Log.d(TAG, "ActivityEmbedding is not supported on this device");
finish();
return;
}
- mEmbeddingComponent.setEmbeddingRules(getSplitRules());
+ embeddingComponent.setEmbeddingRules(getSplitRules());
}
private Set<EmbeddingRule> getSplitRules() {
@@ -72,10 +71,10 @@
final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule.Builder(
new Intent().setComponent(
- ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME),
+ ActivityOptions.ActivityEmbedding.PlaceholderSecondaryActivity.COMPONENT),
activity -> activity instanceof ActivityEmbeddingPlaceholderPrimaryActivity,
intent -> intent.getComponent().equals(
- ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME),
+ ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT),
windowMetrics -> true)
.setSplitRatio(DEFAULT_SPLIT_RATIO)
.build();
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index cae3df4..5b1ca1f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -19,94 +19,181 @@
import android.content.ComponentName;
public class ActivityOptions {
- public static final String EXTRA_STARVE_UI_THREAD = "StarveUiThread";
public static final String FLICKER_APP_PACKAGE = "com.android.server.wm.flicker.testapp";
- public static final String SEAMLESS_ACTIVITY_LAUNCHER_NAME = "SeamlessApp";
- public static final ComponentName SEAMLESS_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".SeamlessRotationActivity");
+ public static class SimpleActivity {
+ public static final String LABEL = "SimpleActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SimpleActivity");
+ }
- public static final String IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME = "ImeAppAutoFocus";
- public static final ComponentName IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".ImeActivityAutoFocus");
+ public static class SeamlessRotation {
+ public static final String LABEL = "SeamlessRotationActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SeamlessRotationActivity");
- public static final String IME_ACTIVITY_LAUNCHER_NAME = "ImeActivity";
- public static final ComponentName IME_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
+ public static final String EXTRA_STARVE_UI_THREAD = "StarveUiThread";
+ }
+
+ public static class Ime {
+ public static class Default {
+ public static final String LABEL = "ImeActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ImeActivity");
+ }
- public static final String IME_ACTIVITY_INITIALIZE_LAUNCHER_NAME = "ImeStateInitializeActivity";
- public static final ComponentName IME_ACTIVITY_INITIALIZE_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
+ public static class AutoFocusActivity {
+ public static final String LABEL = "ImeAppAutoFocus";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ImeActivityAutoFocus");
+ }
+
+ public static class StateInitializeActivity {
+ public static final String LABEL = "ImeStateInitializeActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ImeStateInitializeActivity");
+ }
- public static final String SIMPLE_ACTIVITY_LAUNCHER_NAME = "SimpleApp";
- public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".SimpleActivity");
-
- public static final String NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME = "NonResizeableApp";
- public static final ComponentName NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".NonResizeableActivity");
-
- public static final String BUTTON_ACTIVITY_LAUNCHER_NAME = "ButtonApp";
- public static final ComponentName BUTTON_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".ButtonActivity");
-
- public static final String LAUNCH_NEW_TASK_ACTIVITY_LAUNCHER_NAME = "LaunchNewTaskApp";
- public static final ComponentName LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".LaunchNewTaskActivity");
-
- public static final String DIALOG_THEMED_ACTIVITY = "DialogThemedActivity";
- public static final ComponentName DIALOG_THEMED_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".DialogThemedActivity");
-
- public static final String PORTRAIT_ONLY_ACTIVITY_LAUNCHER_NAME = "PortraitOnlyActivity";
- public static final ComponentName PORTRAIT_ONLY_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".PortraitOnlyActivity");
-
- public static final String EDITOR_POPUP_DIALOG_ACTIVITY_LAUNCHER_NAME =
- "ImeEditorPopupDialogActivity";
- public static final ComponentName EDITOR_POPUP_DIALOG_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
+ public static class EditorPopupDialogActivity {
+ public static final String LABEL = "ImeEditorPopupDialogActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ImeEditorPopupDialogActivity");
+ }
+ }
- public static final String SHOW_WHEN_LOCKED_ACTIVITY_LAUNCHER_NAME = "ShowWhenLockedApp";
- public static final ComponentName SHOW_WHEN_LOCKED_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".ShowWhenLockedActivity");
+ public static class NonResizeableActivity {
+ public static final String LABEL = "NonResizeableActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".NonResizeableActivity");
+ }
- public static final String NOTIFICATION_ACTIVITY_LAUNCHER_NAME = "NotificationApp";
- public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".NotificationActivity");
+ public static class DialogThemedActivity {
+ public static final String LABEL = "DialogThemedActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".DialogThemedActivity");
+ }
- public static final String ACTIVITY_EMBEDDING_LAUNCHER_NAME = "ActivityEmbeddingMainActivity";
- public static final ComponentName ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
+ public static class PortraitOnlyActivity {
+ public static final String LABEL = "PortraitOnlyActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".PortraitOnlyActivity");
+ public static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
+ }
+
+ public static class ActivityEmbedding {
+ public static class MainActivity {
+ public static final String LABEL = "ActivityEmbeddingMainActivity";
+ public static final ComponentName COMPONENT = 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");
+ }
- public static final String MAIL_ACTIVITY_LAUNCHER_NAME = "MailActivity";
- public static final ComponentName MAIL_ACTIVITY_COMPONENT_NAME = new ComponentName(
- FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".MailActivity");
+ public static class PlaceholderPrimaryActivity {
+ public static final String LABEL = "ActivityEmbeddingPlaceholderPrimaryActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderPrimaryActivity");
+ }
- public static final String GAME_ACTIVITY_LAUNCHER_NAME = "GameApp";
- public static final ComponentName GAME_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".GameActivity");
+ public static class PlaceholderSecondaryActivity {
+ public static final String LABEL = "ActivityEmbeddingPlaceholderSecondaryActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
+ }
+ }
+
+ public static class Notification {
+ public static final String LABEL = "NotificationActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".NotificationActivity");
+ }
+
+ public static class Mail {
+ public static final String LABEL = "MailActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".MailActivity");
+ }
+
+ public static class ShowWhenLockedActivity {
+ public static final String LABEL = "ShowWhenLockedActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ShowWhenLockedActivity");
+ }
+
+ public static class LaunchNewTask {
+ public static final String LABEL = "LaunchNewTaskActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".LaunchNewTaskActivity");
+ }
+
+ public static class Game {
+ public static final String LABEL = "GameActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".GameActivity");
+ }
+
+ public static class LaunchNewActivity {
+ public static final String LABEL = "LaunchNewActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".LaunchNewActivity");
+ }
+
+ public static class PipActivity {
+ // Test App > Pip Activity
+ public static final String LABEL = "PipActivity";
+ public static final String MENU_ACTION_NO_OP = "No-Op";
+ public static final String MENU_ACTION_ON = "On";
+ public static final String MENU_ACTION_OFF = "Off";
+ public static final String MENU_ACTION_CLEAR = "Clear";
+
+ // Intent action that this activity dynamically registers to enter picture-in-picture
+ public static final String ACTION_ENTER_PIP =
+ FLICKER_APP_PACKAGE + ".PipActivity.ENTER_PIP";
+ // Intent action that this activity dynamically registers to set requested orientation.
+ // Will apply the oriention to the value set in the EXTRA_FIXED_ORIENTATION extra.
+ public static final String ACTION_SET_REQUESTED_ORIENTATION =
+ FLICKER_APP_PACKAGE + ".PipActivity.SET_REQUESTED_ORIENTATION";
+
+ // Calls enterPictureInPicture() on creation
+ public static final String EXTRA_ENTER_PIP = "enter_pip";
+ // Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
+ public static final String EXTRA_PIP_ORIENTATION = "fixed_orientation";
+ // Adds a click listener to finish this activity when it is clicked
+ public static final String EXTRA_TAP_TO_FINISH = "tap_to_finish";
+
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".PipActivity");
+ }
+
+ public static class SplitScreenActivity {
+ public static class Primary {
+ public static final String LABEL = "SplitScreenPrimaryActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SplitScreenActivity");
+ }
+
+ public static class Secondary {
+ public static final String LABEL = "SplitScreenSecondaryActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SplitScreenSecondaryActivity");
+ }
+ }
+
+ public static class SendNotificationActivity {
+ public static final String LABEL = "SendNotificationActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SendNotificationActivity");
+ }
+
+ public static class Bubbles {
+ public static class LaunchBubble {
+ public static final String LABEL = "LaunchBubbleActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".LaunchBubbleActivity");
+ }
+
+ public static class BubbleActivity {
+ public static final String LABEL = "BubbleActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".BubbleActivity");
+ }
+ }
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BubbleActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BubbleActivity.java
new file mode 100644
index 0000000..58d7e67
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BubbleActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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.content.Intent;
+import android.os.Bundle;
+import android.widget.Toast;
+
+public class BubbleActivity extends Activity {
+ private int mNotifId = 0;
+
+ public BubbleActivity() {
+ super();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ if (intent != null) {
+ mNotifId = intent.getIntExtra(BubbleHelper.EXTRA_BUBBLE_NOTIF_ID, -1);
+ } else {
+ mNotifId = -1;
+ }
+
+ setContentView(R.layout.activity_bubble);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ String result = resultCode == Activity.RESULT_OK ? "OK" : "CANCELLED";
+ Toast.makeText(this, "Activity result: " + result, Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BubbleHelper.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BubbleHelper.java
new file mode 100644
index 0000000..c92b82b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BubbleHelper.java
@@ -0,0 +1,173 @@
+/*
+ * 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.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.drawable.Icon;
+import android.os.SystemClock;
+import android.service.notification.StatusBarNotification;
+import android.view.WindowManager;
+
+import java.util.HashMap;
+
+public class BubbleHelper {
+
+ static final String EXTRA_BUBBLE_NOTIF_ID = "EXTRA_BUBBLE_NOTIF_ID";
+ static final String CHANNEL_ID = "bubbles";
+ static final String CHANNEL_NAME = "Bubbles";
+ static final int DEFAULT_HEIGHT_DP = 300;
+
+ private static BubbleHelper sInstance;
+
+ private final Context mContext;
+ private NotificationManager mNotificationManager;
+ private float mDisplayHeight;
+
+ private HashMap<Integer, BubbleInfo> mBubbleMap = new HashMap<>();
+
+ private int mNextNotifyId = 0;
+ private int mColourIndex = 0;
+
+ public static class BubbleInfo {
+ public int id;
+ public int height;
+ public Icon icon;
+
+ public BubbleInfo(int id, int height, Icon icon) {
+ this.id = id;
+ this.height = height;
+ this.icon = icon;
+ }
+ }
+
+ public static BubbleHelper getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new BubbleHelper(context);
+ }
+ return sInstance;
+ }
+
+ private BubbleHelper(Context context) {
+ mContext = context;
+ mNotificationManager = context.getSystemService(NotificationManager.class);
+
+ NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setDescription("Channel that posts bubbles");
+ channel.setAllowBubbles(true);
+ mNotificationManager.createNotificationChannel(channel);
+
+ Point p = new Point();
+ WindowManager wm = context.getSystemService(WindowManager.class);
+ wm.getDefaultDisplay().getRealSize(p);
+ mDisplayHeight = p.y;
+
+ }
+
+ private int getNextNotifyId() {
+ int id = mNextNotifyId;
+ mNextNotifyId++;
+ return id;
+ }
+
+ private Icon getIcon() {
+ return Icon.createWithResource(mContext, R.drawable.bg);
+ }
+
+ public int addNewBubble(boolean autoExpand, boolean suppressNotif) {
+ int id = getNextNotifyId();
+ BubbleInfo info = new BubbleInfo(id, DEFAULT_HEIGHT_DP, getIcon());
+ mBubbleMap.put(info.id, info);
+
+ Notification.BubbleMetadata data = getBubbleBuilder(info)
+ .setSuppressNotification(suppressNotif)
+ .setAutoExpandBubble(false)
+ .build();
+ Notification notification = getNotificationBuilder(info.id)
+ .setBubbleMetadata(data).build();
+
+ mNotificationManager.notify(info.id, notification);
+ return info.id;
+ }
+
+ private Notification.Builder getNotificationBuilder(int id) {
+ Person chatBot = new Person.Builder()
+ .setBot(true)
+ .setName("BubbleChat")
+ .setImportant(true)
+ .build();
+ String shortcutId = "BubbleChat";
+ return new Notification.Builder(mContext, CHANNEL_ID)
+ .setChannelId(CHANNEL_ID)
+ .setShortcutId(shortcutId)
+ .setContentTitle("BubbleChat")
+ .setContentIntent(PendingIntent.getActivity(mContext, 0,
+ new Intent(mContext, LaunchBubbleActivity.class),
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setStyle(new Notification.MessagingStyle(chatBot)
+ .setConversationTitle("BubbleChat")
+ .addMessage("BubbleChat",
+ SystemClock.currentThreadTimeMillis() - 300000, chatBot)
+ .addMessage("Is it me, " + id + ", you're looking for?",
+ SystemClock.currentThreadTimeMillis(), chatBot)
+ )
+ .setSmallIcon(R.drawable.ic_bubble);
+ }
+
+ private Notification.BubbleMetadata.Builder getBubbleBuilder(BubbleInfo info) {
+ Intent target = new Intent(mContext, BubbleActivity.class);
+ target.putExtra(EXTRA_BUBBLE_NOTIF_ID, info.id);
+ PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, info.id, target,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ return new Notification.BubbleMetadata.Builder()
+ .setIntent(bubbleIntent)
+ .setIcon(info.icon)
+ .setDesiredHeight(info.height);
+ }
+
+ public void cancel(int id) {
+ mNotificationManager.cancel(id);
+ }
+
+ public void cancelAll() {
+ mNotificationManager.cancelAll();
+ }
+
+ public void cancelLast() {
+ StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
+ if (activeNotifications.length > 0) {
+ mNotificationManager.cancel(
+ activeNotifications[activeNotifications.length - 1].getId());
+ }
+ }
+
+ public void cancelFirst() {
+ StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
+ if (activeNotifications.length > 0) {
+ mNotificationManager.cancel(activeNotifications[0].getId());
+ }
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/FixedActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/FixedActivity.java
new file mode 100644
index 0000000..722929f
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/FixedActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION;
+
+import android.os.Bundle;
+
+public class FixedActivity extends SimpleActivity {
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Set the fixed orientation if requested
+ if (getIntent().hasExtra(EXTRA_FIXED_ORIENTATION)) {
+ final int ori = Integer.parseInt(getIntent().getStringExtra(EXTRA_FIXED_ORIENTATION));
+ setRequestedOrientation(ori);
+ }
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchBubbleActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchBubbleActivity.java
new file mode 100644
index 0000000..dea3444
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchBubbleActivity.java
@@ -0,0 +1,82 @@
+/*
+ * 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.app.Person;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.view.View;
+
+import java.util.Arrays;
+
+public class LaunchBubbleActivity extends Activity {
+
+ private BubbleHelper mBubbleHelper;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addInboxShortcut(getApplicationContext());
+ mBubbleHelper = BubbleHelper.getInstance(this);
+ setContentView(R.layout.activity_main);
+ findViewById(R.id.button_create).setOnClickListener(this::add);
+ findViewById(R.id.button_cancel).setOnClickListener(this::cancel);
+ findViewById(R.id.button_cancel_all).setOnClickListener(this::cancelAll);
+ }
+
+ private void add(View v) {
+ mBubbleHelper.addNewBubble(false /* autoExpand */, false /* suppressNotif */);
+ }
+
+ private void cancel(View v) {
+ mBubbleHelper.cancelLast();
+ }
+
+ private void cancelAll(View v) {
+ mBubbleHelper.cancelAll();
+ }
+
+ private void addInboxShortcut(Context context) {
+ Icon icon = Icon.createWithResource(this, R.drawable.bg);
+ Person[] persons = new Person[4];
+ for (int i = 0; i < persons.length; i++) {
+ persons[i] = new Person.Builder()
+ .setBot(false)
+ .setIcon(icon)
+ .setName("google" + i)
+ .setImportant(true)
+ .build();
+ }
+
+ ShortcutInfo shortcut = new ShortcutInfo.Builder(context, "BubbleChat")
+ .setShortLabel("BubbleChat")
+ .setLongLived(true)
+ .setIntent(new Intent(Intent.ACTION_VIEW))
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_message))
+ .setPersons(persons)
+ .build();
+ ShortcutManager scmanager = context.getSystemService(ShortcutManager.class);
+ scmanager.addDynamicShortcuts(Arrays.asList(shortcut));
+ }
+
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
similarity index 87%
rename from tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
rename to tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
index b42ac2a..e5710c8 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
@@ -22,7 +22,7 @@
import android.view.WindowManager;
import android.widget.Button;
-public class ButtonActivity extends Activity {
+public class LaunchNewActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -30,11 +30,11 @@
p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(p);
- setContentView(R.layout.activity_button);
+ setContentView(R.layout.activity_launch_new);
Button button = findViewById(R.id.launch_second_activity);
button.setOnClickListener(v -> {
- Intent intent = new Intent(ButtonActivity.this, SimpleActivity.class);
+ Intent intent = new Intent(LaunchNewActivity.this, SimpleActivity.class);
startActivity(intent);
});
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
new file mode 100644
index 0000000..cdb1d42
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
@@ -0,0 +1,307 @@
+/*
+ * 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 android.media.MediaMetadata.METADATA_KEY_TITLE;
+import static android.media.session.PlaybackState.ACTION_PAUSE;
+import static android.media.session.PlaybackState.ACTION_PLAY;
+import static android.media.session.PlaybackState.ACTION_STOP;
+import static android.media.session.PlaybackState.STATE_PAUSED;
+import static android.media.session.PlaybackState.STATE_PLAYING;
+import static android.media.session.PlaybackState.STATE_STOPPED;
+
+import static com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_SET_REQUESTED_ORIENTATION;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.Pip.EXTRA_ENTER_PIP;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.Pip.EXTRA_PIP_ORIENTATION;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.PictureInPictureParams;
+import android.app.RemoteAction;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
+import android.media.MediaMetadata;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.Rational;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.CheckBox;
+import android.widget.RadioButton;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class PipActivity extends Activity {
+ private static final String TAG = PipActivity.class.getSimpleName();
+ /**
+ * A media session title for when the session is in {@link STATE_PLAYING}.
+ * TvPipNotificationTests check whether the actual notification title matches this string.
+ */
+ private static final String TITLE_STATE_PLAYING = "TestApp media is playing";
+ /**
+ * A media session title for when the session is in {@link STATE_PAUSED}.
+ * TvPipNotificationTests check whether the actual notification title matches this string.
+ */
+ private static final String TITLE_STATE_PAUSED = "TestApp media is paused";
+
+ private static final Rational RATIO_DEFAULT = null;
+ private static final Rational RATIO_SQUARE = new Rational(1, 1);
+ private static final Rational RATIO_WIDE = new Rational(2, 1);
+ private static final Rational RATIO_TALL = new Rational(1, 2);
+
+ private static final String PIP_ACTION_NO_OP = "No-Op";
+ private static final String PIP_ACTION_OFF = "Off";
+ private static final String PIP_ACTION_ON = "On";
+ private static final String PIP_ACTION_CLEAR = "Clear";
+ private static final String ACTION_NO_OP = "com.android.wm.shell.flicker.testapp.NO_OP";
+ private static final String ACTION_SWITCH_OFF =
+ "com.android.wm.shell.flicker.testapp.SWITCH_OFF";
+ private static final String ACTION_SWITCH_ON = "com.android.wm.shell.flicker.testapp.SWITCH_ON";
+ private static final String ACTION_CLEAR = "com.android.wm.shell.flicker.testapp.CLEAR";
+
+ private final PictureInPictureParams.Builder mPipParamsBuilder =
+ new PictureInPictureParams.Builder()
+ .setAspectRatio(RATIO_DEFAULT);
+ private MediaSession mMediaSession;
+ private final PlaybackState.Builder mPlaybackStateBuilder = new PlaybackState.Builder()
+ .setActions(ACTION_PLAY | ACTION_PAUSE | ACTION_STOP)
+ .setState(STATE_STOPPED, 0, 1f);
+ private PlaybackState mPlaybackState = mPlaybackStateBuilder.build();
+ private final MediaMetadata.Builder mMediaMetadataBuilder = new MediaMetadata.Builder();
+
+ private final List<RemoteAction> mSwitchOffActions = new ArrayList<>();
+ private final List<RemoteAction> mSwitchOnActions = new ArrayList<>();
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (isInPictureInPictureMode()) {
+ switch (intent.getAction()) {
+ case ACTION_SWITCH_ON:
+ mPipParamsBuilder.setActions(mSwitchOnActions);
+ break;
+ case ACTION_SWITCH_OFF:
+ mPipParamsBuilder.setActions(mSwitchOffActions);
+ break;
+ case ACTION_CLEAR:
+ mPipParamsBuilder.setActions(Collections.emptyList());
+ break;
+ case ACTION_NO_OP:
+ return;
+ default:
+ Log.w(TAG, "Unhandled action=" + intent.getAction());
+ return;
+ }
+ setPictureInPictureParams(mPipParamsBuilder.build());
+ } else {
+ switch (intent.getAction()) {
+ case ACTION_ENTER_PIP:
+ enterPip(null);
+ break;
+ case ACTION_SET_REQUESTED_ORIENTATION:
+ setRequestedOrientation(Integer.parseInt(intent.getStringExtra(
+ EXTRA_PIP_ORIENTATION)));
+ break;
+ default:
+ Log.w(TAG, "Unhandled action=" + intent.getAction());
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Window window = getWindow();
+ final WindowManager.LayoutParams layoutParams = window.getAttributes();
+ layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ window.setAttributes(layoutParams);
+
+ setContentView(R.layout.activity_pip);
+
+ findViewById(R.id.media_session_start)
+ .setOnClickListener(v -> updateMediaSessionState(STATE_PLAYING));
+ findViewById(R.id.media_session_stop)
+ .setOnClickListener(v -> updateMediaSessionState(STATE_STOPPED));
+
+ mMediaSession = new MediaSession(this, "WMShell_TestApp");
+ mMediaSession.setPlaybackState(mPlaybackStateBuilder.build());
+ mMediaSession.setCallback(new MediaSession.Callback() {
+ @Override
+ public void onPlay() {
+ updateMediaSessionState(STATE_PLAYING);
+ }
+
+ @Override
+ public void onPause() {
+ updateMediaSessionState(STATE_PAUSED);
+ }
+
+ @Override
+ public void onStop() {
+ updateMediaSessionState(STATE_STOPPED);
+ }
+ });
+
+ // Build two sets of the custom actions. We'll replace one with the other when 'On'/'Off'
+ // action is invoked.
+ // The first set consists of 3 actions: 1) Off; 2) No-Op; 3) Clear.
+ // The second set consists of 2 actions: 1) On; 2) Clear.
+ // Upon invocation 'Clear' action clear-off all the custom actions, including itself.
+ final Icon icon = Icon.createWithResource(this, android.R.drawable.ic_menu_help);
+ final RemoteAction noOpAction = buildRemoteAction(icon, PIP_ACTION_NO_OP, ACTION_NO_OP);
+ final RemoteAction switchOnAction =
+ buildRemoteAction(icon, PIP_ACTION_ON, ACTION_SWITCH_ON);
+ final RemoteAction switchOffAction =
+ buildRemoteAction(icon, PIP_ACTION_OFF, ACTION_SWITCH_OFF);
+ final RemoteAction clearAllAction = buildRemoteAction(icon, PIP_ACTION_CLEAR, ACTION_CLEAR);
+ mSwitchOffActions.addAll(Arrays.asList(switchOnAction, clearAllAction));
+ mSwitchOnActions.addAll(Arrays.asList(noOpAction, switchOffAction, clearAllAction));
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_NO_OP);
+ filter.addAction(ACTION_SWITCH_ON);
+ filter.addAction(ACTION_SWITCH_OFF);
+ filter.addAction(ACTION_CLEAR);
+ filter.addAction(ACTION_SET_REQUESTED_ORIENTATION);
+ filter.addAction(ACTION_ENTER_PIP);
+ registerReceiver(mBroadcastReceiver, filter);
+
+ handleIntentExtra(getIntent());
+ }
+
+ @Override
+ protected void onDestroy() {
+ unregisterReceiver(mBroadcastReceiver);
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onUserLeaveHint() {
+ // Only used when auto PiP is disabled. This is to simulate the behavior that an app
+ // supports regular PiP but not auto PiP.
+ final boolean manuallyEnterPip =
+ ((RadioButton) findViewById(R.id.enter_pip_on_leave_manual)).isChecked();
+ if (manuallyEnterPip) {
+ enterPictureInPictureMode();
+ }
+ }
+
+ private RemoteAction buildRemoteAction(Icon icon, String label, String action) {
+ final Intent intent = new Intent(action);
+ final PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ return new RemoteAction(icon, label, label, pendingIntent);
+ }
+
+ public void enterPip(View v) {
+ final boolean withCustomActions =
+ ((CheckBox) findViewById(R.id.with_custom_actions)).isChecked();
+ mPipParamsBuilder.setActions(
+ withCustomActions ? mSwitchOnActions : Collections.emptyList());
+ enterPictureInPictureMode(mPipParamsBuilder.build());
+ }
+
+ public void onAutoPipSelected(View v) {
+ switch (v.getId()) {
+ case R.id.enter_pip_on_leave_manual:
+ // disable auto enter PiP
+ case R.id.enter_pip_on_leave_disabled:
+ mPipParamsBuilder.setAutoEnterEnabled(false);
+ setPictureInPictureParams(mPipParamsBuilder.build());
+ break;
+ case R.id.enter_pip_on_leave_autoenter:
+ mPipParamsBuilder.setAutoEnterEnabled(true);
+ setPictureInPictureParams(mPipParamsBuilder.build());
+ break;
+ }
+ }
+
+ public void onRatioSelected(View v) {
+ switch (v.getId()) {
+ case R.id.ratio_default:
+ mPipParamsBuilder.setAspectRatio(RATIO_DEFAULT);
+ break;
+
+ case R.id.ratio_square:
+ mPipParamsBuilder.setAspectRatio(RATIO_SQUARE);
+ break;
+
+ case R.id.ratio_wide:
+ mPipParamsBuilder.setAspectRatio(RATIO_WIDE);
+ break;
+
+ case R.id.ratio_tall:
+ mPipParamsBuilder.setAspectRatio(RATIO_TALL);
+ break;
+ }
+ }
+
+ private void updateMediaSessionState(int newState) {
+ if (mPlaybackState.getState() == newState) {
+ return;
+ }
+ final String title;
+ switch (newState) {
+ case STATE_PLAYING:
+ title = TITLE_STATE_PLAYING;
+ break;
+ case STATE_PAUSED:
+ title = TITLE_STATE_PAUSED;
+ break;
+ case STATE_STOPPED:
+ title = "";
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown state " + newState);
+ }
+
+ mPlaybackStateBuilder.setState(newState, 0, 1f);
+ mPlaybackState = mPlaybackStateBuilder.build();
+
+ mMediaMetadataBuilder.putText(METADATA_KEY_TITLE, title);
+
+ mMediaSession.setPlaybackState(mPlaybackState);
+ mMediaSession.setMetadata(mMediaMetadataBuilder.build());
+ mMediaSession.setActive(newState != STATE_STOPPED);
+ }
+
+ private void handleIntentExtra(Intent intent) {
+ // Set the fixed orientation if requested
+ if (intent.hasExtra(EXTRA_PIP_ORIENTATION)) {
+ final int ori = Integer.parseInt(getIntent().getStringExtra(EXTRA_PIP_ORIENTATION));
+ setRequestedOrientation(ori);
+ }
+ // Enter picture in picture with the given aspect ratio if provided
+ if (intent.hasExtra(EXTRA_ENTER_PIP)) {
+ mPipParamsBuilder.setActions(mSwitchOnActions);
+ enterPip(null);
+ }
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
index 5cf81cb..ce7a005 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
@@ -18,7 +18,7 @@
import static android.os.SystemClock.sleep;
-import static com.android.server.wm.flicker.testapp.ActivityOptions.EXTRA_STARVE_UI_THREAD;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD;
import android.app.Activity;
import android.os.Bundle;
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SendNotificationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SendNotificationActivity.java
new file mode 100644
index 0000000..8868488
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SendNotificationActivity.java
@@ -0,0 +1,61 @@
+/*
+ * 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.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+public class SendNotificationActivity extends Activity {
+ private NotificationManager mNotificationManager;
+ private String mChannelId = "Channel id";
+ private String mChannelName = "Channel name";
+ private NotificationChannel mChannel;
+ private int mNotifyId = 0;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_notification);
+ findViewById(R.id.button_send_notification).setOnClickListener(this::sendNotification);
+
+ mChannel = new NotificationChannel(mChannelId, mChannelName,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ mNotificationManager = getSystemService(NotificationManager.class);
+ mNotificationManager.createNotificationChannel(mChannel);
+ }
+
+ private void sendNotification(View v) {
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
+ new Intent(this, SendNotificationActivity.class),
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ Notification notification = new Notification.Builder(this, mChannelId)
+ .setContentTitle("Notification App")
+ .setContentText("Notification content")
+ .setWhen(System.currentTimeMillis())
+ .setSmallIcon(R.drawable.ic_message)
+ .setContentIntent(pendingIntent)
+ .build();
+
+ mNotificationManager.notify(mNotifyId, notification);
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenActivity.java
new file mode 100644
index 0000000..70196ae
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenActivity.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+public class SplitScreenActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.activity_splitscreen);
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenSecondaryActivity.java
new file mode 100644
index 0000000..a8ce8ff
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenSecondaryActivity.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public class SplitScreenSecondaryActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.activity_splitscreen_secondary);
+ }
+}