diff --git a/-e b/-e
new file mode 100644
index 000000000..e69de29bb
diff --git a/app/src/androidTest/assets/pages/audioMediaPage.html b/app/src/androidTest/assets/pages/audioMediaPage.html
new file mode 100644
index 000000000..1a8720a85
--- /dev/null
+++ b/app/src/androidTest/assets/pages/audioMediaPage.html
@@ -0,0 +1,26 @@
+
+
+ Audio_Test_Page
+
+
+Page content: audio player
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/androidTest/assets/pages/videoMediaPage.html b/app/src/androidTest/assets/pages/videoMediaPage.html
new file mode 100644
index 000000000..32baa8d78
--- /dev/null
+++ b/app/src/androidTest/assets/pages/videoMediaPage.html
@@ -0,0 +1,26 @@
+
+
+ Video_Test_Page
+
+
+Page content: video player
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/androidTest/assets/resources/audioSample.mp3 b/app/src/androidTest/assets/resources/audioSample.mp3
new file mode 100644
index 000000000..eb0420a48
Binary files /dev/null and b/app/src/androidTest/assets/resources/audioSample.mp3 differ
diff --git a/app/src/androidTest/assets/resources/videoSample.webm b/app/src/androidTest/assets/resources/videoSample.webm
new file mode 100644
index 000000000..f9afbdde3
Binary files /dev/null and b/app/src/androidTest/assets/resources/videoSample.webm differ
diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt
index 672a0e165..240caaca2 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt
@@ -18,7 +18,7 @@ object TestAssetHelper {
val waitingTime: Long = TimeUnit.SECONDS.toMillis(15)
val waitingTimeShort: Long = TimeUnit.SECONDS.toMillis(1)
- data class TestAsset(val url: Uri, val content: String)
+ data class TestAsset(val url: Uri, val content: String, val title: String)
/**
* Hosts 3 simple websites, found at androidTest/assets/pages/generic[1|2|3].html
@@ -33,7 +33,8 @@ object TestAssetHelper {
return (1..4).map {
TestAsset(
server.url("pages/generic$it.html").toString().toUri()!!,
- "Page content: $it"
+ "Page content: $it",
+ ""
)
}
}
@@ -41,52 +42,70 @@ object TestAssetHelper {
fun getGenericAsset(server: MockWebServer, pageNum: Int): TestAsset {
val url = server.url("pages/generic$pageNum.html").toString().toUri()!!
val content = "Page content: $pageNum"
+ val title = "Test_Page_$pageNum"
- return TestAsset(url, content)
+ return TestAsset(url, content, title)
}
fun getLoremIpsumAsset(server: MockWebServer): TestAsset {
val url = server.url("pages/lorem-ipsum.html").toString().toUri()!!
val content = "Page content: lorem ipsum"
- return TestAsset(url, content)
+
+ return TestAsset(url, content, "")
}
fun getRefreshAsset(server: MockWebServer): TestAsset {
val url = server.url("pages/refresh.html").toString().toUri()!!
val content = "Page content: refresh"
- return TestAsset(url, content)
+ return TestAsset(url, content, "")
}
fun getUUIDPage(server: MockWebServer): TestAsset {
val url = server.url("pages/basic_nav_uuid.html").toString().toUri()!!
val content = "Page content: basic_nav_uuid"
- return TestAsset(url, content)
+ return TestAsset(url, content, "")
}
fun getDownloadAsset(server: MockWebServer): TestAsset {
val url = server.url("pages/download.html").toString().toUri()!!
val content = "Page content: Globe.svg"
- return TestAsset(url, content)
+ return TestAsset(url, content, "")
}
fun getEnhancedTrackingProtectionAsset(server: MockWebServer): TestAsset {
val url = server.url("pages/etp.html").toString().toUri()!!
- return TestAsset(url, "")
+ return TestAsset(url, "", "")
}
fun getImageAsset(server: MockWebServer): TestAsset {
val url = server.url("resources/rabbit.jpg").toString().toUri()!!
- return TestAsset(url, "")
+ return TestAsset(url, "", "")
}
fun getSaveLoginAsset(server: MockWebServer): TestAsset {
val url = server.url("pages/password.html").toString().toUri()!!
- return TestAsset(url, "")
+ return TestAsset(url, "", "")
+ }
+
+ fun getAudioPageAsset(server: MockWebServer): TestAsset {
+ val url = server.url("pages/audioMediaPage.html").toString().toUri()!!
+ val title = "Audio_Test_Page"
+ val content = "Page content: audio player"
+
+ return TestAsset(url, content, title)
+ }
+
+ fun getVideoPageAsset(server: MockWebServer): TestAsset {
+ val url = server.url("pages/videoMediaPage.html").toString().toUri()!!
+ val title = "Video_Test_Page"
+ val content = "Page content: video player"
+
+ return TestAsset(url, content, title)
}
}
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt
new file mode 100644
index 000000000..67e2ad16d
--- /dev/null
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt
@@ -0,0 +1,131 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.ui
+
+import okhttp3.mockwebserver.MockWebServer
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mozilla.fenix.helpers.AndroidAssetDispatcher
+import org.mozilla.fenix.helpers.HomeActivityTestRule
+import org.mozilla.fenix.helpers.TestAssetHelper
+import org.mozilla.fenix.ui.robots.browserScreen
+import org.mozilla.fenix.ui.robots.homeScreen
+import org.mozilla.fenix.ui.robots.mDevice
+import org.mozilla.fenix.ui.robots.navigationToolbar
+
+/**
+ * Tests for verifying basic functionality of media notifications:
+ * - video and audio playback system notifications appear and can pause/play the media content
+ * - a media notification icon is displayed on the homescreen for the tab playing media content
+ * Note: this test only verifies media notifications, not media itself
+ */
+class MediaNotificationTest {
+ /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
+
+ private lateinit var mockWebServer: MockWebServer
+
+ @get:Rule
+ val activityTestRule = HomeActivityTestRule()
+
+ @Before
+ fun setUp() {
+ mockWebServer = MockWebServer().apply {
+ setDispatcher(AndroidAssetDispatcher())
+ start()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mockWebServer.shutdown()
+ }
+
+ @Test
+ fun videoPlaybackSystemNotificationTest() {
+ val videoTestPage = TestAssetHelper.getVideoPageAsset(mockWebServer)
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(videoTestPage.url) {
+ clickMediaPlayerPlayButton()
+ waitForPlaybackToStart()
+ }.openNotificationShade {
+ verifySystemNotificationExists(videoTestPage.title)
+ clickMediaSystemNotificationControlButton("Pause")
+ verifyMediaSystemNotificationButtonState("Play")
+ }
+
+ mDevice.pressBack()
+
+ browserScreen {
+ verifyMediaIsPaused()
+ }
+ }
+
+ @Test
+ fun audioPlaybackSystemNotificationTest() {
+ val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer)
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(audioTestPage.url) {
+ verifyPageContent(audioTestPage.content)
+ clickMediaPlayerPlayButton()
+ waitForPlaybackToStart()
+ }.openNotificationShade {
+ verifySystemNotificationExists(audioTestPage.title)
+ clickMediaSystemNotificationControlButton("Pause")
+ verifyMediaSystemNotificationButtonState("Play")
+ }
+
+ mDevice.pressBack()
+
+ browserScreen {
+ verifyMediaIsPaused()
+ }
+ }
+
+ @Test
+ fun tabMediaControlButtonTest() {
+ val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer)
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(audioTestPage.url) {
+ verifyPageContent(audioTestPage.content)
+ clickMediaPlayerPlayButton()
+ waitForPlaybackToStart()
+ }.openHomeScreen {
+ verifyTabMediaControlButtonState("Pause")
+ clickTabMediaControlButton()
+ verifyTabMediaControlButtonState("Play")
+ }.openTab(audioTestPage.title) {
+ verifyMediaIsPaused()
+ }
+ }
+
+ @Test
+ fun mediaSystemNotificationInPrivateModeTest() {
+ val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer)
+
+ homeScreen { }.togglePrivateBrowsingMode()
+
+ navigationToolbar {
+ }.enterURLAndEnterToBrowser(audioTestPage.url) {
+ verifyPageContent(audioTestPage.content)
+ clickMediaPlayerPlayButton()
+ waitForPlaybackToStart()
+ }.openNotificationShade {
+ verifySystemNotificationExists("A site is playing media")
+ clickMediaSystemNotificationControlButton("Pause")
+ verifyMediaSystemNotificationButtonState("Play")
+ }
+
+ mDevice.pressBack()
+
+ browserScreen {
+ verifyMediaIsPaused()
+ }
+ }
+}
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt
index 09244e360..d48856747 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt
@@ -19,6 +19,7 @@ import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.ext.waitNotNull
import org.mozilla.fenix.ui.robots.homeScreen
import org.mozilla.fenix.ui.robots.navigationToolbar
+import org.mozilla.fenix.ui.robots.notificationShade
/**
* Tests for verifying basic functionality of tabbed browsing
@@ -259,6 +260,9 @@ class TabbedBrowsingTest {
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
mDevice.openNotification()
+ }
+
+ notificationShade {
verifyPrivateTabsNotification()
}.clickClosePrivateTabsNotification {
verifyPrivateSessionMessage()
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt
index 33f78df17..7b2cda964 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt
@@ -26,6 +26,7 @@ import androidx.test.uiautomator.By.text
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.Until
+import androidx.test.uiautomator.Until.hasObject
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.containsString
import org.junit.Assert.assertTrue
@@ -34,6 +35,7 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.helpers.Constants.LongClickDuration
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
+import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort
import org.mozilla.fenix.helpers.click
import org.mozilla.fenix.helpers.ext.waitNotNull
@@ -57,7 +59,7 @@ class BrowserRobot {
)
TestAssetHelper.waitingTime
onView(withId(R.id.mozac_browser_toolbar_url_view))
- .check(matches(withText(containsString(url.replace("http://", "")))))
+ .check(matches(withText(containsString(url.replace("http://", "")))))
}
fun verifyHelpUrl() {
@@ -145,11 +147,6 @@ class BrowserRobot {
)
}
- fun verifyPrivateTabsNotification() {
- mDevice.wait(Until.hasObject(text("Close private tabs")), waitingTime)
- assertPrivateTabsNotification()
- }
-
fun clickContextOpenLinkInNewTab() {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mDevice.waitNotNull(
@@ -289,6 +286,36 @@ class BrowserRobot {
mDevice.findObject(text(optionToSaveLogin)).click()
}
+ fun clickMediaPlayerPlayButton() {
+ mDevice.waitNotNull(
+ hasObject(
+ By
+ .clazz("android.widget.Button")
+ .textContains("Play")
+ ),
+ waitingTime
+ )
+ mediaPlayerPlayButton().click()
+ }
+
+ fun waitForPlaybackToStart() {
+ mDevice.waitNotNull(
+ hasObject(
+ text("Media file is playing")
+ ), waitingTimeShort
+ )
+ }
+
+ fun verifyMediaIsPaused() {
+ mDevice.waitNotNull(
+ hasObject(
+ text("Media file is paused")
+ ), waitingTimeShort
+ )
+
+ mDevice.findObject(UiSelector().text("Media file is paused")).exists()
+ }
+
class Transition {
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private fun threeDotButton() = onView(
@@ -329,12 +356,11 @@ class BrowserRobot {
return HomeScreenRobot.Transition()
}
- fun clickClosePrivateTabsNotification(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
- mDevice.wait(Until.hasObject(text("Close private tabs")), waitingTime)
- closePrivateTabsNotification().clickAndWaitForNewWindow(waitingTime)
+ fun openNotificationShade(interact: NotificationRobot.() -> Unit): NotificationRobot.Transition {
+ mDevice.openNotification()
- HomeScreenRobot().interact()
- return HomeScreenRobot.Transition()
+ NotificationRobot().interact()
+ return NotificationRobot.Transition()
}
}
}
@@ -355,10 +381,9 @@ fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
private fun tabsCounter() = onView(withId(R.id.mozac_browser_toolbar_browser_actions))
-private fun closePrivateTabsNotification() =
- mDevice.findObject(UiSelector().text("Close private tabs"))
-
-private fun assertPrivateTabsNotification() {
- mDevice.findObject(UiSelector().text("Firefox Preview (Private)")).exists()
- mDevice.findObject(UiSelector().text("Close private tabs")).exists()
-}
+private fun mediaPlayerPlayButton() =
+ mDevice.findObject(
+ By
+ .clazz("android.widget.Button")
+ .textContains("Play")
+ )
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt
index d23e68e0a..b87c4e3cb 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt
@@ -6,8 +6,8 @@
package org.mozilla.fenix.ui.robots
-import androidx.recyclerview.widget.RecyclerView
import android.graphics.Bitmap
+import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.click
@@ -16,30 +16,32 @@ import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
import androidx.test.espresso.matcher.ViewMatchers
-import androidx.test.espresso.matcher.ViewMatchers.withId
-import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
+import androidx.test.uiautomator.By.text
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiScrollable
import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.Until
-import org.hamcrest.CoreMatchers.containsString
+import androidx.test.uiautomator.Until.findObject
import org.hamcrest.CoreMatchers.allOf
+import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.CoreMatchers.not
import org.mozilla.fenix.R
+import org.mozilla.fenix.components.Search
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.click
import org.mozilla.fenix.helpers.ext.waitNotNull
-import org.mozilla.fenix.components.Search
-import org.mozilla.fenix.helpers.withBitmapDrawable
import org.mozilla.fenix.helpers.matchers.hasItem
+import org.mozilla.fenix.helpers.withBitmapDrawable
/**
* Implementation of Robot Pattern for the home screen menu.
@@ -168,7 +170,8 @@ class HomeScreenRobot {
fun swipeToBottom() = onView(withId(R.id.homeLayout)).perform(ViewActions.swipeUp())
- fun swipeToTop() = onView(withId(R.id.sessionControlRecyclerView)).perform(ViewActions.swipeDown())
+ fun swipeToTop() =
+ onView(withId(R.id.sessionControlRecyclerView)).perform(ViewActions.swipeDown())
fun swipeTabRight(title: String) =
onView(allOf(withId(R.id.tab_title), withText(title))).perform(ViewActions.swipeRight())
@@ -185,10 +188,21 @@ class HomeScreenRobot {
fun snackBarButtonClick(expectedText: String) {
onView(allOf(withId(R.id.snackbar_btn), withText(expectedText))).check(
- matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))
- ).perform(ViewActions.click())
+ matches(withEffectiveVisibility(Visibility.VISIBLE))
+ ).perform(click())
}
+ fun verifyTabMediaControlButtonState(action: String) {
+ mDevice.waitNotNull(
+ Until.findObject(By.res("org.mozilla.fenix.debug:id/play_pause_button")),
+ waitingTime
+ )
+
+ tabMediaControlButton().check(matches(withContentDescription(action)))
+ }
+
+ fun clickTabMediaControlButton() = tabMediaControlButton().click()
+
class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@@ -242,16 +256,25 @@ class HomeScreenRobot {
return NavigationToolbarRobot.Transition()
}
- fun openContextMenuOnTopSitesWithTitle(title: String, interact: HomeScreenRobot.() -> Unit): Transition {
+ fun openContextMenuOnTopSitesWithTitle(
+ title: String,
+ interact: HomeScreenRobot.() -> Unit
+ ): Transition {
onView(withId(R.id.top_sites_list)).perform(
- actionOnItem(hasDescendant(withText(title)), ViewActions.longClick())
+ actionOnItem(
+ hasDescendant(withText(title)),
+ ViewActions.longClick()
+ )
)
HomeScreenRobot().interact()
return Transition()
}
- fun openTopSiteTabWithTitle(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
+ fun openTopSiteTabWithTitle(
+ title: String,
+ interact: BrowserRobot.() -> Unit
+ ): BrowserRobot.Transition {
onView(withId(R.id.top_sites_list)).perform(
actionOnItem(hasDescendant(withText(title)), click())
)
@@ -280,7 +303,20 @@ class HomeScreenRobot {
fun openCommonMythsLink(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
onView(withId(R.id.private_session_common_myths))
- .perform(click())
+ .perform(click())
+
+ BrowserRobot().interact()
+ return BrowserRobot.Transition()
+ }
+
+ fun openTab(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
+ mDevice.waitNotNull(findObject(text(title)))
+ onView(
+ allOf(
+ withId(R.id.tab_title),
+ withText(title)
+ )
+ ).click()
BrowserRobot().interact()
return BrowserRobot.Transition()
@@ -355,12 +391,12 @@ private fun assertCollectionsHeaderIsNotVisible() =
.check(doesNotExist())
private fun assertNoCollectionsText() =
- onView(
- allOf(
- withText("Collect the things that matter to you. To start, save open tabs to a new collection.")
- )
+ onView(
+ allOf(
+ withText("Collect the things that matter to you. To start, save open tabs to a new collection.")
)
- .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
+ )
+ .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoCollectionsTextIsNotVisible() =
onView(
@@ -370,8 +406,9 @@ private fun assertNoCollectionsTextIsNotVisible() =
)
.check(doesNotExist())
-private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
- .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
+private fun assertHomeComponent() =
+ onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
+ .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
@@ -485,10 +522,10 @@ private fun assertPrivacyNoticeButton() =
// What's new elements
private fun assertWhatsNewHeather() = onView(allOf(withText("See what’s new")))
- .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
+ .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertWhatsNewLink() = onView(allOf(withText("Get answers here")))
- .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
+ .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertStartBrowsingButton() =
onView(allOf(withText("Start browsing")))
@@ -496,18 +533,20 @@ private fun assertStartBrowsingButton() =
// Take a position
private fun assertTakePositionheader() = onView(allOf(withText("Take a position")))
- .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
+ .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
-private fun assertTakePositionTopRadioButton() = onView(ViewMatchers.withResourceName("toolbar_top_radio_button"))
+private fun assertTakePositionTopRadioButton() =
+ onView(ViewMatchers.withResourceName("toolbar_top_radio_button"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
-private fun assertTakePositionBottomRadioButton() = onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button"))
+private fun assertTakePositionBottomRadioButton() =
+ onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
// Private mode elements
private fun assertPrivateSessionHeader() =
onView(allOf(withText("Private tabs")))
- .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
+ .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " +
"when you quit the app or close all private tabs. While this doesn’t make you anonymous to websites or " +
@@ -521,9 +560,11 @@ private fun assertPrivateSessionMessage(visible: Boolean) =
)
private fun assertShareTabsButton(visible: Boolean) = onView(allOf(withId(R.id.share_tabs_button)))
- .check(
- if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else matches(withEffectiveVisibility(Visibility.INVISIBLE))
+ .check(
+ if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else matches(
+ withEffectiveVisibility(Visibility.INVISIBLE)
)
+ )
private fun assertCloseTabsButton(title: String) =
onView(allOf(withId(R.id.close_tab_button), withContentDescription("Close tab $title")))
@@ -588,3 +629,5 @@ private fun assertTopSiteContextMenuItems() {
waitingTime
)
}
+
+private fun tabMediaControlButton() = onView(withId(R.id.play_pause_button))
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt
new file mode 100644
index 000000000..879bf029c
--- /dev/null
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt
@@ -0,0 +1,83 @@
+package org.mozilla.fenix.ui.robots
+
+import android.content.res.Resources
+import androidx.test.uiautomator.By.text
+import androidx.test.uiautomator.UiScrollable
+import androidx.test.uiautomator.UiSelector
+import androidx.test.uiautomator.Until
+import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
+import org.mozilla.fenix.helpers.ext.waitNotNull
+
+class NotificationRobot {
+
+ fun verifySystemNotificationExists(notificationMessage: String) {
+
+ fun notificationTray() = UiScrollable(
+ UiSelector().resourceId("com.android.systemui:id/notification_stack_scroller")
+ )
+
+ mDevice.waitNotNull(
+ Until.hasObject(text(notificationMessage)),
+ waitingTime
+ )
+
+ var notificationFound = false
+ while (!notificationFound) {
+ try {
+ val notification = notificationTray().getChildByText(
+ UiSelector().text(notificationMessage), notificationMessage,
+ true
+ )
+ notification.exists()
+ notificationFound = true
+ } catch (e: Resources.NotFoundException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ fun verifyPrivateTabsNotification() {
+ mDevice.waitNotNull(Until.hasObject(text("Close private tabs")), waitingTime)
+ assertPrivateTabsNotification()
+ }
+
+ fun clickMediaSystemNotificationControlButton(action: String) {
+ mediaSystemNotificationButton(action).waitForExists(waitingTime)
+ mediaSystemNotificationButton(action).click()
+ }
+
+ fun verifyMediaSystemNotificationButtonState(action: String) {
+ mediaSystemNotificationButton(action).waitForExists(waitingTime)
+ }
+
+ class Transition {
+
+ fun clickClosePrivateTabsNotification(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
+ NotificationRobot().verifySystemNotificationExists("Close private tabs")
+ closePrivateTabsNotification().clickAndWaitForNewWindow()
+
+ HomeScreenRobot().interact()
+ return HomeScreenRobot.Transition()
+ }
+ }
+}
+
+fun notificationShade(interact: NotificationRobot.() -> Unit): NotificationRobot.Transition {
+ NotificationRobot().interact()
+ return NotificationRobot.Transition()
+}
+
+private fun assertPrivateTabsNotification() {
+ mDevice.findObject(UiSelector().text("Firefox Preview (Private)")).exists()
+ mDevice.findObject(UiSelector().text("Close private tabs")).exists()
+}
+
+private fun closePrivateTabsNotification() =
+ mDevice.findObject(UiSelector().text("Close private tabs"))
+
+private fun mediaSystemNotificationButton(action: String) =
+ mDevice.findObject(
+ UiSelector()
+ .resourceId("android:id/action0")
+ .descriptionContains(action)
+ )