From 757e60e05726d28a7c8b5f79930d501cee74af7c Mon Sep 17 00:00:00 2001 From: Sergey Nikolaienkov Date: Mon, 2 Nov 2020 08:42:50 +0000 Subject: [PATCH] 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 --- .../Shell/tests/flicker/AndroidManifest.xml | 9 ++ .../wm/shell/flicker/FlickerTestBase.kt | 4 + .../wm/shell/flicker/NotificationListener.kt | 89 ++++++++++++++++++ .../com/android/wm/shell/flicker/WaitUtils.kt | 45 +++++++++ .../flicker/pip/tv/TvPipNotificationTests.kt | 92 +++++++++++++++++++ .../wm/shell/flicker/pip/tv/TvPipTestBase.kt | 44 +++++++++ 6 files changed, 283 insertions(+) create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml index 967e853b6a48a..58fc90e4d8275 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml @@ -36,6 +36,15 @@ + + + + + + = 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 0000000000000..a6d67355f2711 --- /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 waitForResult( + timeout: Long = DEFAULT_TIMEOUT, + interval: Long = DEFAULT_POLL_INTERVAL, + extractor: () -> R, + validator: (R) -> Boolean = { it != null } +): Pair { + 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 0000000000000..569da1ddd953d --- /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> { + 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 0000000000000..104248c64dddf --- /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