diff options
| author | 2020-11-02 08:42:50 +0000 | |
|---|---|---|
| committer | 2020-11-04 12:32:51 +0000 | |
| commit | 757e60e05726d28a7c8b5f79930d501cee74af7c (patch) | |
| tree | 1afc263a1dbb64a4ef90142760d86bbc3d50612e | |
| parent | 58dc55b6e84f32124a907fd9f44e55ee7a5fbeae (diff) | |
Introduce .wm.flicker.pip.tv.TvPipNotificationTests
Move first test out of android.systemui.cts.tv.PipNotificationTests to
com.android.wm.shell.flicker.pip.tv.TvPipNotification tests.
Bug: 171520419
Test: atest WMShellFlickerTests:TvPipNotificationTests
Change-Id: I6a3e2fb96a7688814ce909f28d6d904356fad3fd
6 files changed, 283 insertions, 0 deletions
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml index 967e853b6a48..58fc90e4d827 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml @@ -36,6 +36,15 @@ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/> <application> <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> </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt index 99f824bb8341..75b55c1e6a9f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.flicker +import android.content.pm.PackageManager import android.os.RemoteException import android.os.SystemClock import android.platform.helpers.IAppHelper @@ -41,6 +42,9 @@ abstract class FlickerTestBase { val uiDevice by lazy { UiDevice.getInstance(instrumentation) } + val packageManager: PackageManager by lazy { + instrumentation.context.getPackageManager() + } /** * Build a test tag for the test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt new file mode 100644 index 000000000000..5c7ec30ecd3e --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt @@ -0,0 +1,89 @@ +/* + * 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 com.android.wm.shell.flicker + +import android.service.notification.NotificationListenerService +import android.service.notification.StatusBarNotification +import android.util.Log +import com.android.compatibility.common.util.SystemUtil.runShellCommand + +class NotificationListener : NotificationListenerService() { + private val notifications: MutableMap<Any, StatusBarNotification> = mutableMapOf() + + override fun onNotificationPosted(sbn: StatusBarNotification) { + if (DEBUG) Log.d(TAG, "onNotificationPosted: $sbn") + notifications[sbn.key] = sbn + } + + override fun onNotificationRemoved(sbn: StatusBarNotification) { + if (DEBUG) Log.d(TAG, "onNotificationRemoved: $sbn") + notifications.remove(sbn.key) + } + + override fun onListenerConnected() { + if (DEBUG) Log.d(TAG, "onListenerConnected") + instance = this + } + + override fun onListenerDisconnected() { + if (DEBUG) Log.d(TAG, "onListenerDisconnected") + instance = null + notifications.clear() + } + + companion object { + private const val DEBUG = false + private const val TAG = "WMShellFlickerTests_NotificationListener" + + private const val CMD_NOTIFICATION_ALLOW_LISTENER = "cmd notification allow_listener %s" + private const val CMD_NOTIFICATION_DISALLOW_LISTENER = + "cmd notification disallow_listener %s" + private const val COMPONENT_NAME = "com.android.wm.shell.flicker/.NotificationListener" + + private var instance: NotificationListener? = null + + fun startNotificationListener(): Boolean { + if (instance != null) { + return true + } + + runShellCommand(CMD_NOTIFICATION_ALLOW_LISTENER.format(COMPONENT_NAME)) + return wait { instance != null } + } + + fun stopNotificationListener(): Boolean { + if (instance == null) { + return true + } + + runShellCommand(CMD_NOTIFICATION_DISALLOW_LISTENER.format(COMPONENT_NAME)) + return wait { instance == null } + } + + fun waitForNotificationToAppear(predicate: (StatusBarNotification) -> Boolean): Boolean { + return instance?.let { + wait { it.notifications.values.any(predicate) } + } ?: throw IllegalStateException("NotificationListenerService is not connected") + } + + fun waitForNotificationToDisappear(predicate: (StatusBarNotification) -> Boolean): Boolean { + return instance?.let { + wait { it.notifications.values.none(predicate) } + } ?: throw IllegalStateException("NotificationListenerService is not connected") + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt new file mode 100644 index 000000000000..a6d67355f271 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt @@ -0,0 +1,45 @@ +/* + * 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 com.android.wm.shell.flicker + +import android.os.SystemClock + +private const val DEFAULT_TIMEOUT = 10000L +private const val DEFAULT_POLL_INTERVAL = 1000L + +fun wait(condition: () -> Boolean): Boolean { + val (success, _) = waitForResult(extractor = condition, validator = { it }) + return success +} + +fun <R> waitForResult( + timeout: Long = DEFAULT_TIMEOUT, + interval: Long = DEFAULT_POLL_INTERVAL, + extractor: () -> R, + validator: (R) -> Boolean = { it != null } +): Pair<Boolean, R?> { + val startTime = SystemClock.uptimeMillis() + do { + val result = extractor() + if (validator(result)) { + return (true to result) + } + SystemClock.sleep(interval) + } while (SystemClock.uptimeMillis() - startTime < timeout) + + return (false to null) +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt new file mode 100644 index 000000000000..569da1ddd953 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt @@ -0,0 +1,92 @@ +/* + * 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 com.android.wm.shell.flicker.pip.tv + +import android.app.Notification +import android.service.notification.StatusBarNotification +import android.view.Surface +import androidx.test.filters.RequiresDevice +import com.android.wm.shell.flicker.NotificationListener.Companion.startNotificationListener +import com.android.wm.shell.flicker.NotificationListener.Companion.stopNotificationListener +import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToAppear +import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToDisappear +import org.junit.After +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test Pip Notifications on TV. + * To run this test: `atest WMShellFlickerTests:TvPipNotificationTests` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class TvPipNotificationTests(rotationName: String, rotation: Int) + : TvPipTestBase(rotationName, rotation) { + + @Before + override fun setUp() { + super.setUp() + val started = startNotificationListener() + if (!started) { + error("NotificationListener hasn't started") + } + } + + @After + override fun tearDown() { + stopNotificationListener() + testApp.forceStop() + super.tearDown() + } + + @Test + fun pipNotification_postedAndDismissed() { + testApp.launchViaIntent() + testApp.clickEnterPipButton() + + assertTrue("Pip notification should have been posted", + waitForNotificationToAppear { it.isPipNotificationWithTitle(testApp.label) }) + + testApp.closePipWindow() + + assertTrue("Pip notification should have been dismissed", + waitForNotificationToDisappear { it.isPipNotificationWithTitle(testApp.label) }) + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val supportedRotations = intArrayOf(Surface.ROTATION_0) + return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } + } + } +} + +private const val PIP_NOTIFICATION_TAG = "PipNotification" + +private val StatusBarNotification.title: String + get() = notification?.extras?.getString(Notification.EXTRA_TITLE) ?: "" + +private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean = + tag == PIP_NOTIFICATION_TAG && title == expectedTitle
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt new file mode 100644 index 000000000000..104248c64ddd --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt @@ -0,0 +1,44 @@ +/* + * 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 com.android.wm.shell.flicker.pip.tv + +import android.content.pm.PackageManager.FEATURE_LEANBACK +import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.pip.PipTestBase +import org.junit.After +import org.junit.Assume +import org.junit.Before + +abstract class TvPipTestBase(rotationName: String, rotation: Int) + : PipTestBase(rotationName, rotation) { + + private val isTelevision: Boolean + get() = packageManager.run { + hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY) + } + + @Before + open fun setUp() { + Assume.assumeTrue(isTelevision) + uiDevice.wakeUpAndGoToHomeScreen() + } + + @After + open fun tearDown() { + } +}
\ No newline at end of file |