summaryrefslogtreecommitdiffstats
path: root/mobile/android/android-components/components/feature/privatemode/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
commitda4c7e7ed675c3bf405668739c3012d140856109 (patch)
treecdd868dba063fecba609a1d819de271f0d51b23e /mobile/android/android-components/components/feature/privatemode/src
parentAdding upstream version 125.0.3. (diff)
downloadfirefox-da4c7e7ed675c3bf405668739c3012d140856109.tar.xz
firefox-da4c7e7ed675c3bf405668739c3012d140856109.zip
Adding upstream version 126.0.upstream/126.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mobile/android/android-components/components/feature/privatemode/src')
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/AndroidManifest.xml8
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/feature/SecureWindowFeature.kt58
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationService.kt261
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeature.kt49
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-am/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-an/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ar/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ast/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-az/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-azb/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ban/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-be/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-bg/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-bn/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-br/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-bs/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ca/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-cak/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ceb/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ckb/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-co/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-cs/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-cy/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-da/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-de/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-dsb/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-el/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rCA/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rGB/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-eo/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rAR/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rCL/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rES/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rMX/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-es/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-et/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-eu/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-fa/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-fi/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-fr/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-fur/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-fy-rNL/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-gd/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-gl/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-gn/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-gu-rIN/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-hi-rIN/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-hr/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-hsb/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-hu/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-hy-rAM/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ia/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-in/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-is/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-it/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-iw/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ja/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ka/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-kaa/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-kab/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-kk/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-kmr/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-kn/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ko/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-lo/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-lt/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-mr/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-my/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-nb-rNO/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ne-rNP/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-nl/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-nn-rNO/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-oc/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rIN/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rPK/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-pl/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rBR/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rPT/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-rm/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ro/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ru/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-sat/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-sc/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-si/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-sk/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-skr/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-sl/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-sq/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-sr/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-su/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-sv-rSE/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ta/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-te/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-tg/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-th/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-tl/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-tr/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-trs/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-tt/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ug/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-uk/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-ur/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-uz/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-vi/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-yo/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rCN/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rTW/strings.xml5
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/main/res/values/strings.xml8
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/feature/SecureWindowFeatureTest.kt90
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationServiceTest.kt195
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeatureTest.kt133
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker2
-rw-r--r--mobile/android/android-components/components/feature/privatemode/src/test/resources/robolectric.properties1
113 files changed, 1320 insertions, 0 deletions
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/AndroidManifest.xml b/mobile/android/android-components/components/feature/privatemode/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..5fba0d9762
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/AndroidManifest.xml
@@ -0,0 +1,8 @@
+<!-- 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/. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
+</manifest>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/feature/SecureWindowFeature.kt b/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/feature/SecureWindowFeature.kt
new file mode 100644
index 0000000000..388fd30388
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/feature/SecureWindowFeature.kt
@@ -0,0 +1,58 @@
+/* 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 mozilla.components.feature.privatemode.feature
+
+import android.view.Window
+import android.view.WindowManager.LayoutParams.FLAG_SECURE
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapNotNull
+import mozilla.components.browser.state.selector.findCustomTabOrSelectedTab
+import mozilla.components.browser.state.state.SessionState
+import mozilla.components.browser.state.store.BrowserStore
+import mozilla.components.lib.state.ext.flowScoped
+import mozilla.components.support.base.feature.LifecycleAwareFeature
+
+/**
+ * Prevents screenshots and screen recordings in private tabs.
+ *
+ * @param isSecure Returns true if the session should have [FLAG_SECURE] set.
+ * @param clearFlagOnStop Used to keep [FLAG_SECURE] enabled or not when calling [stop].
+ * Can be overriden to customize when the secure flag is set.
+ */
+class SecureWindowFeature(
+ private val window: Window,
+ private val store: BrowserStore,
+ private val customTabId: String? = null,
+ private val isSecure: (SessionState) -> Boolean = { it.content.private },
+ private val clearFlagOnStop: Boolean = true,
+) : LifecycleAwareFeature {
+
+ private var scope: CoroutineScope? = null
+
+ override fun start() {
+ scope = store.flowScoped { flow ->
+ flow.mapNotNull { state -> state.findCustomTabOrSelectedTab(customTabId) }
+ .map { isSecure(it) }
+ .distinctUntilChanged()
+ .collect { isSecure ->
+ if (isSecure) {
+ window.addFlags(FLAG_SECURE)
+ } else {
+ window.clearFlags(FLAG_SECURE)
+ }
+ }
+ }
+ }
+
+ override fun stop() {
+ scope?.cancel()
+ if (clearFlagOnStop) {
+ window.clearFlags(FLAG_SECURE)
+ }
+ }
+}
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationService.kt b/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationService.kt
new file mode 100644
index 0000000000..638c36356e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationService.kt
@@ -0,0 +1,261 @@
+/* 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 mozilla.components.feature.privatemode.notification
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_ONE_SHOT
+import android.app.Service
+import android.content.Intent
+import android.os.Build
+import android.os.Build.VERSION.SDK_INT
+import android.os.IBinder
+import androidx.annotation.CallSuper
+import androidx.annotation.VisibleForTesting
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationCompat.VISIBILITY_SECRET
+import androidx.core.app.NotificationManagerCompat.IMPORTANCE_LOW
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import mozilla.components.browser.state.action.TabListAction
+import mozilla.components.browser.state.selector.privateTabs
+import mozilla.components.browser.state.store.BrowserStore
+import mozilla.components.feature.privatemode.R
+import mozilla.components.lib.state.ext.flowScoped
+import mozilla.components.support.base.android.NotificationsDelegate
+import mozilla.components.support.base.ids.SharedIdsHelper
+import mozilla.components.support.ktx.android.notification.ChannelData
+import mozilla.components.support.ktx.android.notification.ensureNotificationChannelExists
+import mozilla.components.support.utils.PendingIntentUtils
+import mozilla.components.support.utils.ext.stopForegroundCompat
+import java.util.Locale
+
+/**
+ * Manages notifications for private tabs.
+ *
+ * Private tab notifications solve two problems:
+ * 1. They allow users to interact with the browser from outside of the app
+ * (example: by closing all private tabs).
+ * 2. The notification will keep the process alive, allowing the browser to
+ * keep private tabs in memory.
+ *
+ * As long as a private tab is open this service will keep its notification alive.
+ */
+@Suppress("TooManyFunctions")
+abstract class AbstractPrivateNotificationService(
+ private val notificationScope: CoroutineScope = CoroutineScope(Dispatchers.IO),
+) : Service() {
+ private var privateTabsScope: CoroutineScope? = null
+ private var localeScope: CoroutineScope? = null
+
+ abstract val store: BrowserStore
+ abstract val notificationsDelegate: NotificationsDelegate
+
+ /**
+ * Customizes the private browsing notification.
+ */
+ abstract fun NotificationCompat.Builder.buildNotification()
+
+ /**
+ * Customize the notification response when the [Locale] has been changed.
+ */
+ abstract fun notifyLocaleChanged()
+
+ /**
+ * Erases all private tabs in reaction to the user tapping the notification.
+ */
+ @CallSuper
+ protected open fun erasePrivateTabs() {
+ store.dispatch(TabListAction.RemoveAllPrivateTabsAction)
+ }
+
+ /**
+ * Retrieves the notification id based on the tag.
+ */
+ protected fun getNotificationId(): Int {
+ return SharedIdsHelper.getIdForTag(this, NOTIFICATION_TAG)
+ }
+
+ /**
+ * Retrieves the channel id based on the channel data.
+ */
+ protected fun getChannelId(): String {
+ return ensureNotificationChannelExists(
+ this,
+ NOTIFICATION_CHANNEL,
+ onSetupChannel = {
+ if (SDK_INT >= Build.VERSION_CODES.O) {
+ enableLights(false)
+ enableVibration(false)
+ setShowBadge(false)
+ }
+ },
+ )
+ }
+
+ /**
+ * Re-build and notify an existing notification.
+ */
+ protected fun refreshNotification() {
+ notificationScope.launch {
+ val notificationId = getNotificationId()
+ val channelId = getChannelId()
+
+ val notification = createNotification(channelId)
+ withContext(Dispatchers.Main) {
+ notificationsDelegate.notify(notificationId = notificationId, notification = notification)
+ }
+ }
+ }
+
+ /**
+ * Create the private browsing notification and
+ * add a listener to stop the service once all private tabs are closed.
+ *
+ * The service should be started only if private tabs are open.
+ */
+ final override fun onCreate() {
+ notificationScope.launch {
+ val notificationId = getNotificationId()
+ val channelId = getChannelId()
+ val notification = createNotification(channelId)
+
+ if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ notificationsDelegate.requestNotificationPermission(
+ onPermissionGranted = { refreshNotification() },
+ )
+ }
+
+ withContext(Dispatchers.Main) {
+ startForeground(notificationId, notification)
+ }
+ }
+
+ privateTabsScope = store.flowScoped { flow ->
+ flow.map { state -> state.privateTabs.isEmpty() }
+ .distinctUntilChanged()
+ .collect { noPrivateTabs ->
+ if (noPrivateTabs) stopService()
+ }
+ }
+
+ localeScope = store.flowScoped { flow ->
+ flow.mapNotNull { state -> state.locale }
+ .distinctUntilChanged()
+ .collect {
+ notifyLocaleChanged()
+ }
+ }
+ }
+
+ /**
+ * Builds a notification based on the specified channel id.
+ *
+ * @param channelId The channel id for the [Notification]
+ */
+ private fun createNotification(channelId: String): Notification {
+ val eraseIntent = Intent(ACTION_ERASE).let { intent ->
+ intent.setClass(this, this::class.java)
+ PendingIntent.getService(
+ this,
+ 0,
+ intent,
+ PendingIntentUtils.defaultFlags or FLAG_ONE_SHOT,
+ )
+ }
+
+ return NotificationCompat.Builder(this, channelId)
+ .setOngoing(true)
+ .setVisibility(VISIBILITY_SECRET)
+ .setShowWhen(false)
+ .setLocalOnly(true)
+ .setContentIntent(eraseIntent)
+ .apply {
+ if (SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ setDeleteIntent(eraseIntent)
+ }
+
+ buildNotification()
+ }
+ .build()
+ }
+
+ final override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ if (intent.action == ACTION_ERASE) {
+ erasePrivateTabs()
+ }
+
+ return START_NOT_STICKY
+ }
+
+ final override fun onDestroy() {
+ privateTabsScope?.cancel()
+ localeScope?.cancel()
+ }
+
+ final override fun onBind(intent: Intent?): IBinder? = null
+
+ final override fun onTaskRemoved(rootIntent: Intent) {
+ if (rootIntent.action in defaultIgnoreTaskActions ||
+ rootIntent.action in ignoreTaskActions() ||
+ rootIntent.component?.className in ignoreTaskComponentClasses()
+ ) {
+ // The app may have multiple tasks (e.g. for PWAs). If tasks get removed that are not
+ // the main browser task then we do not want to remove all private tabs here.
+ // I am not sure whether we can reliably identify the main task since it can be launched
+ // from multiple entry points (e.g. the launcher, VIEW intents, ..).
+ // So instead we ignore tasks with root intents that we absolutely do not want to handle
+ // here (e.g. PWAs) and then extend the list if needed.
+ return
+ }
+
+ store.dispatch(TabListAction.RemoveAllPrivateTabsAction)
+ stopService()
+ }
+
+ private fun stopService() {
+ stopForegroundCompat(true)
+ stopSelf()
+ }
+
+ /**
+ * Builds a list of Intent actions that will get ignored
+ * when they are in the root intent that gets passed to onTaskRemoved().
+ *
+ */
+ abstract fun ignoreTaskActions(): List<String>
+
+ /**
+ * Builds a list of Intent components' qualified class name that will get ignored
+ * when they are in the root intent that gets passed to onTaskRemoved().
+ *
+ */
+ abstract fun ignoreTaskComponentClasses(): List<String>
+
+ companion object {
+ private const val NOTIFICATION_TAG =
+ "mozilla.components.feature.privatemode.notification.AbstractPrivateNotificationService"
+ const val ACTION_ERASE = "mozilla.components.feature.privatemode.action.ERASE"
+
+ val NOTIFICATION_CHANNEL = ChannelData(
+ id = "browsing-session",
+ name = R.string.mozac_feature_privatemode_notification_channel_name,
+ importance = IMPORTANCE_LOW,
+ )
+
+ // List of default Intent actions that will get ignored
+ // when they are in the root intent that gets passed to onTaskRemoved().
+ @VisibleForTesting
+ internal val defaultIgnoreTaskActions = listOf(
+ "mozilla.components.feature.pwa.VIEW_PWA",
+ )
+ }
+}
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeature.kt b/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeature.kt
new file mode 100644
index 0000000000..2dc3086fd5
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeature.kt
@@ -0,0 +1,49 @@
+/* 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 mozilla.components.feature.privatemode.notification
+
+import android.content.Context
+import android.content.Intent
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import mozilla.components.browser.state.selector.privateTabs
+import mozilla.components.browser.state.store.BrowserStore
+import mozilla.components.lib.state.ext.flowScoped
+import mozilla.components.support.base.feature.LifecycleAwareFeature
+import kotlin.reflect.KClass
+
+/**
+ * Starts up a [AbstractPrivateNotificationService] once a private tab is opened.
+ *
+ * @param store Browser store reference used to observe the number of private tabs.
+ * @param notificationServiceClass The service sub-class that should be started by this feature.
+ */
+class PrivateNotificationFeature<T : AbstractPrivateNotificationService>(
+ context: Context,
+ private val store: BrowserStore,
+ private val notificationServiceClass: KClass<T>,
+) : LifecycleAwareFeature {
+
+ private val applicationContext = context.applicationContext
+ private var scope: CoroutineScope? = null
+
+ override fun start() {
+ scope = store.flowScoped { flow ->
+ flow.map { state -> state.privateTabs.isNotEmpty() }
+ .distinctUntilChanged()
+ .collect { hasPrivateTabs ->
+ if (hasPrivateTabs) {
+ applicationContext.startService(Intent(applicationContext, notificationServiceClass.java))
+ }
+ }
+ }
+ }
+
+ override fun stop() {
+ scope?.cancel()
+ }
+}
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-am/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000000..187c4d8cfa
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-am/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">የግል አሰሳ ክፍለ ጊዜ</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-an/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-an/strings.xml
new file mode 100644
index 0000000000..d775e46430
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-an/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de navegación privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ar/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000000..d2f4886a0e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ar/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">جلسة تصفح خاصة</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ast/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ast/strings.xml
new file mode 100644
index 0000000000..457d635755
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ast/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de restolar en privao</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-az/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-az/strings.xml
new file mode 100644
index 0000000000..55f7e0792b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-az/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Məxfi səyahət sessiyası</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-azb/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-azb/strings.xml
new file mode 100644
index 0000000000..ec6fc61308
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-azb/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">گیزلی مورور اوتورومو</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ban/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ban/strings.xml
new file mode 100644
index 0000000000..fa07631f1a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ban/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesi parerehan pribadi</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-be/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000000..b8139d2113
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-be/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Сеанс прыватнага аглядання</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bg/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000000..ef4231310e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bg/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Поверителна сесия</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bn/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000000..202a4f48c4
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bn/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">ব্যক্তিগত ব্রাউজিং সেশন</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-br/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-br/strings.xml
new file mode 100644
index 0000000000..7f5fbe5d6d
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-br/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Estez merdeiñ prevez</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bs/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000000..257e347741
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-bs/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesija privatnog surfanja</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ca/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000000..a8bba4c5eb
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ca/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sessió de navegació privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cak/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cak/strings.xml
new file mode 100644
index 0000000000..345b325348
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cak/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Ichinan okem pa k\'amaya\'l</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ceb/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ceb/strings.xml
new file mode 100644
index 0000000000..02d5db9319
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ceb/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Pribado nga browsing session</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ckb/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ckb/strings.xml
new file mode 100644
index 0000000000..afdd152d2d
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ckb/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">دانیشتنی گەڕانی تایبەت</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-co/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-co/strings.xml
new file mode 100644
index 0000000000..f0b94247ed
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-co/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sessione di navigazione privata</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cs/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000000..01b363ad88
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cs/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Relace anonymního prohlížení</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cy/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cy/strings.xml
new file mode 100644
index 0000000000..3a32633f6e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-cy/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesiwn pori preifat</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-da/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000000..d3e9ad0c56
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-da/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privat browsing-session</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-de/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000000..6962068c23
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-de/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Private Surf-Sitzung</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-dsb/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-dsb/strings.xml
new file mode 100644
index 0000000000..6e32fee374
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-dsb/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Priwatne pósejźenje</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-el/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000000..44c884a333
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-el/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Συνεδρία ιδιωτικής περιήγησης</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rCA/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000000..587e57a1dc
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rCA/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Private browsing session</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rGB/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000000..587e57a1dc
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Private browsing session</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-eo/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-eo/strings.xml
new file mode 100644
index 0000000000..24e839434f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-eo/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Seanco de privata retumo</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rAR/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rAR/strings.xml
new file mode 100644
index 0000000000..d775e46430
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rAR/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de navegación privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rCL/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rCL/strings.xml
new file mode 100644
index 0000000000..d775e46430
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rCL/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de navegación privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rES/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rES/strings.xml
new file mode 100644
index 0000000000..d775e46430
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rES/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de navegación privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rMX/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rMX/strings.xml
new file mode 100644
index 0000000000..d775e46430
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es-rMX/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de navegación privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000000..d775e46430
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-es/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de navegación privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-et/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000000..818868f7b1
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-et/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privaatse veebilehitsemise seanss</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-eu/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000000..ce1cc77225
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-eu/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Nabigatze pribatuko saioa</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fa/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000000..1b0ab6cdc2
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fa/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">نشستِ مرور ناشناس</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fi/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000000..ad96bb66cf
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fi/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Yksityinen selausistunto</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fr/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000000..712fb939b8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Session de navigation privée</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fur/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fur/strings.xml
new file mode 100644
index 0000000000..d24e91d19b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fur/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Session di navigazion privade</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fy-rNL/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fy-rNL/strings.xml
new file mode 100644
index 0000000000..0bf34311e7
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-fy-rNL/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Priveenavigaasjesesje</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gd/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gd/strings.xml
new file mode 100644
index 0000000000..8064f0b6e2
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gd/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Seisean brabhsaidh prìobhaideach</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gl/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000000..d775e46430
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gl/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesión de navegación privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gn/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gn/strings.xml
new file mode 100644
index 0000000000..eaaef34716
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gn/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Tembiapo kundaha ñemíme</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gu-rIN/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gu-rIN/strings.xml
new file mode 100644
index 0000000000..bc1ed90389
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-gu-rIN/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">ખાનગી બ્રાઉઝિંગ સત્ર</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hi-rIN/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hi-rIN/strings.xml
new file mode 100644
index 0000000000..0cf2bf22be
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hi-rIN/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">निजी ब्राउज़िंग सत्र</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hr/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000000..17a3aa688e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesija privatnog pretraživanja</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hsb/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hsb/strings.xml
new file mode 100644
index 0000000000..78f71ed53b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hsb/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Priwatne posedźenje</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hu/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000000..b58ef5be53
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hu/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privát böngészési munkamenet</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hy-rAM/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000000..1c0211b44d
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-hy-rAM/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Գանղտնի դիտարկման աշխատաշրջան</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ia/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ia/strings.xml
new file mode 100644
index 0000000000..b299198ddc
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ia/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Session de navigation private</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-in/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000000..fd7bcd9b30
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-in/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesi penjelajahan pribadi</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-is/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000000..b85189898b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-is/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Huliðsvafurlota</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-it/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000000..449c79bace
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-it/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sessione di navigazione anonima</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-iw/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000000..1ac361ffc5
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-iw/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">הפעלה בגלישה פרטית</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ja/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000000..e57c06a447
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ja/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">プライベートブラウジングセッション</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ka/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000000..99846f0b5f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ka/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">პირადი დათვალიერების სეანსი</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kaa/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kaa/strings.xml
new file mode 100644
index 0000000000..04f25b68ba
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kaa/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Jeke kóriw seansı</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kab/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kab/strings.xml
new file mode 100644
index 0000000000..cddb5621a7
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kab/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Tiɣimit n tunigin tusligt</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kk/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000000..d8545dba12
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kk/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Жекелік шолу сессиясы</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kmr/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kmr/strings.xml
new file mode 100644
index 0000000000..f49d779df7
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kmr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Rûniştina gerîna veşartî</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kn/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000000..66fb25b0e0
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-kn/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">ಖಾಸಗಿ ಬ್ರೌಸಿಂಗ್ ಸೆಷನ್</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ko/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000000..58fc1a45ca
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ko/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">사생활 보호 모드 세션</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-lo/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000000..97397e1dc8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-lo/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">ເຊສຊັນການທ່ອງເວັບແບບສ່ວນຕົວ</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-lt/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000000..fa2849bd50
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-lt/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privačiojo naršymo seansas</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-mr/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000000..2501d4d94e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-mr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">खाजगी ब्राऊझिंग सत्र</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-my/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000000..1b1da5b38c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-my/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">သီးသန့်ကြည့်ရှုခြင်းပုံစံ</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nb-rNO/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nb-rNO/strings.xml
new file mode 100644
index 0000000000..7159bbe9bf
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nb-rNO/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privat nettlesingsøkt</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ne-rNP/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ne-rNP/strings.xml
new file mode 100644
index 0000000000..82a848084f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ne-rNP/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">निजी ब्राउजिङ्ग सत्र</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nl/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000000..c51408466e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nl/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privénavigatiesessie</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nn-rNO/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nn-rNO/strings.xml
new file mode 100644
index 0000000000..7159bbe9bf
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-nn-rNO/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privat nettlesingsøkt</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-oc/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-oc/strings.xml
new file mode 100644
index 0000000000..9214c4fa23
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-oc/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Session de navegacion privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rIN/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rIN/strings.xml
new file mode 100644
index 0000000000..9d636d882c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rIN/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">ਨਿੱਜੀ ਬਰਾਊਜ਼ ਕਰਨ ਦਾ ਸ਼ੈਸ਼ਨ</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rPK/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rPK/strings.xml
new file mode 100644
index 0000000000..3d7e304a13
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pa-rPK/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">نجی ورتوں</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pl/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000000..786b051c52
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pl/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesja trybu prywatnego</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rBR/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000000..2febb65f6a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sessão de navegação privativa</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rPT/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000000..da6a1e8dc3
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sessão de navegação privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-rm/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-rm/strings.xml
new file mode 100644
index 0000000000..9371c80689
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-rm/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesida da navigaziun privata</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ro/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000000..a2965d814a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ro/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesiune de navigare privată</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ru/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000000..5971b2bb61
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ru/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Приватный просмотр</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sat/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sat/strings.xml
new file mode 100644
index 0000000000..3d20f4bd6f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sat/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">ᱯᱨᱭᱣᱮᱴ ᱵᱽᱨᱟᱣᱩᱡᱤᱸᱜ ᱠᱟᱹᱢᱤ </string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sc/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sc/strings.xml
new file mode 100644
index 0000000000..7db20cd453
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sc/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sessione de navigatzione privada</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-si/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000000..ebd851ac52
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-si/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">පෞද්. පිරික්සුම් වාරය</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sk/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000000..9f430d7176
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sk/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Súkromné prehliadanie</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-skr/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-skr/strings.xml
new file mode 100644
index 0000000000..971f535406
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-skr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">نجی براؤزنگ سیشن</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sl/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000000..8ef95bda09
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sl/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Seja zasebnega brskanja</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sq/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000000..ff918d3e51
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sq/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sesion shfletimi privat</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sr/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000000..95acbc3bb3
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Сесија за приватно прегледање</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-su/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-su/strings.xml
new file mode 100644
index 0000000000..a85f313c02
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-su/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Rintakan pamaluruhan nyamuni</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sv-rSE/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sv-rSE/strings.xml
new file mode 100644
index 0000000000..497edd6bac
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-sv-rSE/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Privat surfsession</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ta/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000000..9521d4a790
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ta/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">கமுக்க உலாவல் அமர்வு</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-te/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000000..93bbc2f4b8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-te/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">అంతరంగిక విహరణ సెషను</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tg/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tg/strings.xml
new file mode 100644
index 0000000000..db6d7f325b
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tg/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Ҷаласаи тамошокунии хусусӣ</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-th/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000000..001877e436
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-th/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">วาระการท่องเว็บแบบส่วนตัว</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tl/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000000..587e57a1dc
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tl/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Private browsing session</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tr/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000000..4bf45da6c7
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Gizli gezinti oturumu</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-trs/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-trs/strings.xml
new file mode 100644
index 0000000000..1b699c60a1
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-trs/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Sēsiûn riña gāchē nu huìt</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tt/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tt/strings.xml
new file mode 100644
index 0000000000..683fb8376c
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-tt/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Хосусый гизү утырышы</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ug/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ug/strings.xml
new file mode 100644
index 0000000000..94e8d8ba72
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ug/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">شەخسىي زىيارەت سۆزلەشكۈ</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-uk/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000000..8145544044
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-uk/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Сеанс приватного перегляду</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ur/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000000..971f535406
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-ur/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">نجی براؤزنگ سیشن</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-uz/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-uz/strings.xml
new file mode 100644
index 0000000000..268840ae3f
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-uz/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Maxfiy koʻrish seansi</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-vi/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000000..894f23f484
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-vi/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Phiên duyệt web riêng tư</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-yo/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-yo/strings.xml
new file mode 100644
index 0000000000..0bf23890c5
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-yo/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Àkókò bíráwúsìnìn ìkọ̀kọ̀</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rCN/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000000..c30e937dda
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">隐私浏览会话</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rTW/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000000..badb8f5119
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">隱私瀏覽階段</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/main/res/values/strings.xml b/mobile/android/android-components/components/feature/privatemode/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..82a3bbd38e
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<resources>
+ <!-- The user visible name of the "notification channel" (Android 8+ feature) for the ongoing notification shown while a browsing session is active. -->
+ <string name="mozac_feature_privatemode_notification_channel_name">Private browsing session</string>
+</resources>
diff --git a/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/feature/SecureWindowFeatureTest.kt b/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/feature/SecureWindowFeatureTest.kt
new file mode 100644
index 0000000000..d35709751a
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/feature/SecureWindowFeatureTest.kt
@@ -0,0 +1,90 @@
+/* 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 mozilla.components.feature.privatemode.feature
+
+import android.view.Window
+import android.view.WindowManager.LayoutParams.FLAG_SECURE
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import mozilla.components.browser.state.state.BrowserState
+import mozilla.components.browser.state.state.createTab
+import mozilla.components.browser.state.store.BrowserStore
+import mozilla.components.support.test.mock
+import mozilla.components.support.test.rule.MainCoroutineRule
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@ExperimentalCoroutinesApi
+class SecureWindowFeatureTest {
+
+ @get:Rule
+ val coroutinesTestRule = MainCoroutineRule()
+
+ private lateinit var window: Window
+ private val tabId = "test-tab"
+
+ @Before
+ fun setup() {
+ window = mock()
+ }
+
+ @Test
+ fun `no-op if no sessions`() {
+ val store = BrowserStore(BrowserState(tabs = emptyList()))
+ val feature = SecureWindowFeature(window, store)
+
+ feature.start()
+
+ verify(window, never()).addFlags(FLAG_SECURE)
+ verify(window, never()).clearFlags(FLAG_SECURE)
+ }
+
+ @Test
+ fun `add flags to private session`() {
+ val store = BrowserStore(
+ BrowserState(
+ tabs = listOf(
+ createTab("https://www.mozilla.org", id = tabId, private = true),
+ ),
+ selectedTabId = tabId,
+ ),
+ )
+ val feature = SecureWindowFeature(window, store)
+
+ feature.start()
+
+ verify(window).addFlags(FLAG_SECURE)
+ }
+
+ @Test
+ fun `remove flags from normal session`() {
+ val store = BrowserStore(
+ BrowserState(
+ tabs = listOf(
+ createTab("https://www.mozilla.org", id = tabId, private = false),
+ ),
+ selectedTabId = tabId,
+ ),
+ )
+ val feature = SecureWindowFeature(window, store)
+
+ feature.start()
+
+ verify(window).clearFlags(FLAG_SECURE)
+ }
+
+ @Test
+ fun `remove flags on stop`() {
+ val store = BrowserStore()
+ val feature = SecureWindowFeature(window, store, clearFlagOnStop = true)
+
+ feature.start()
+ feature.stop()
+
+ verify(window).clearFlags(FLAG_SECURE)
+ }
+}
diff --git a/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationServiceTest.kt b/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationServiceTest.kt
new file mode 100644
index 0000000000..615caf4123
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/AbstractPrivateNotificationServiceTest.kt
@@ -0,0 +1,195 @@
+/* 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 mozilla.components.feature.privatemode.notification
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.app.Service
+import android.content.ComponentName
+import android.content.Intent
+import android.content.SharedPreferences
+import androidx.core.app.NotificationCompat
+import androidx.core.content.getSystemService
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
+import mozilla.components.browser.state.action.LocaleAction
+import mozilla.components.browser.state.action.TabListAction
+import mozilla.components.browser.state.state.BrowserState
+import mozilla.components.browser.state.store.BrowserStore
+import mozilla.components.feature.privatemode.notification.AbstractPrivateNotificationService.Companion.ACTION_ERASE
+import mozilla.components.feature.privatemode.notification.AbstractPrivateNotificationService.Companion.defaultIgnoreTaskActions
+import mozilla.components.support.base.android.NotificationsDelegate
+import mozilla.components.support.test.argumentCaptor
+import mozilla.components.support.test.ext.joinBlocking
+import mozilla.components.support.test.mock
+import mozilla.components.support.test.robolectric.testContext
+import mozilla.components.support.test.rule.MainCoroutineRule
+import mozilla.components.support.test.rule.runTestOnMain
+import mozilla.components.support.test.whenever
+import mozilla.components.support.utils.ext.stopForegroundCompat
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mockito
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import java.util.Locale
+
+@ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
+class AbstractPrivateNotificationServiceTest {
+
+ @get:Rule
+ val coroutinesTestRule = MainCoroutineRule()
+ private val dispatcher = coroutinesTestRule.testDispatcher
+
+ private lateinit var preferences: SharedPreferences
+ private lateinit var notificationManager: NotificationManager
+
+ @Before
+ fun setup() {
+ preferences = mock()
+ notificationManager = mock()
+ val editor = mock<SharedPreferences.Editor>()
+
+ whenever(preferences.edit()).thenReturn(editor)
+ whenever(editor.putLong(anyString(), anyLong())).thenReturn(editor)
+ }
+
+ @Test
+ fun `WHEN the service is created THEN start foreground is called`() = runTestOnMain {
+ val service = spy(
+ object : MockService(scope = this@runTestOnMain) {
+ override fun NotificationCompat.Builder.buildNotification() {
+ setCategory(Notification.CATEGORY_STATUS)
+ }
+ override fun notifyLocaleChanged() {
+ // NOOP
+ }
+ },
+ )
+ attachContext(service)
+
+ val notification = argumentCaptor<Notification>()
+ service.onCreate()
+ advanceUntilIdle()
+
+ verify(service).startForeground(anyInt(), notification.capture())
+ assertEquals(Notification.CATEGORY_STATUS, notification.value.category)
+ }
+
+ @Test
+ fun `GIVEN an erase intent is received THEN remove all private tabs`() {
+ val service = MockService()
+ val result = service.onStartCommand(Intent(ACTION_ERASE), 0, 0)
+
+ verify(service.store).dispatch(TabListAction.RemoveAllPrivateTabsAction)
+ assertEquals(Service.START_NOT_STICKY, result)
+ }
+
+ @Test
+ fun `WHEN task is removed THEN all private tabs are removed`() {
+ val service = spy(MockService())
+ service.onTaskRemoved(mock())
+
+ verify(service.store).dispatch(TabListAction.RemoveAllPrivateTabsAction)
+ verify(service).stopForegroundCompat(true)
+ verify(service).stopSelf()
+ }
+
+ @Test
+ fun `WHEN task is removed with ignored intents THEN do nothing`() {
+ val service = spy(MockService())
+
+ val mockTaskActions = listOf("action1", "action2")
+ whenever(service.ignoreTaskActions()).then { mockTaskActions }
+
+ (mockTaskActions + defaultIgnoreTaskActions).forEach { it ->
+ service.onTaskRemoved(Intent(it))
+
+ verify(service.store, never()).dispatch(TabListAction.RemoveAllPrivateTabsAction)
+ verify(service, never()).stopForegroundCompat(true)
+ verify(service, never()).stopSelf()
+ }
+
+ val mockTaskCompoentClasses = listOf(
+ "org.mozilla.fenix.IntentReceiverActivity",
+ "org.mozilla.fenix.customtabs.ExternalAppBrowserActivity",
+ "comp1",
+ "comp2",
+ )
+ whenever(service.ignoreTaskComponentClasses()).then { mockTaskCompoentClasses }
+
+ mockTaskCompoentClasses.forEach { it ->
+ service.onTaskRemoved(Intent().setComponent(ComponentName(testContext, it)))
+
+ verify(service.store, never()).dispatch(TabListAction.RemoveAllPrivateTabsAction)
+ verify(service, never()).stopForegroundCompat(true)
+ verify(service, never()).stopSelf()
+ }
+ }
+
+ @Test
+ fun `WHEN a locale change is made in the browser store THEN the service should notify`() {
+ val service = spy(MockServiceWithStore())
+ attachContext(service)
+ service.onCreate()
+
+ val mockLocale = Locale("English")
+ service.store.dispatch(LocaleAction.UpdateLocaleAction(mockLocale)).joinBlocking()
+ dispatcher.scheduler.advanceUntilIdle()
+
+ verify(service).notifyLocaleChanged()
+ }
+
+ private open class MockService(scope: CoroutineScope = TestScope()) :
+ AbstractPrivateNotificationService(scope) {
+ override val store: BrowserStore = spy(BrowserStore())
+ override val notificationsDelegate: NotificationsDelegate = mock()
+
+ override fun NotificationCompat.Builder.buildNotification() = Unit
+ override fun notifyLocaleChanged() {
+ // NOOP
+ }
+
+ override fun ignoreTaskActions(): List<String> = mock()
+ override fun ignoreTaskComponentClasses(): List<String> = mock()
+ }
+
+ private open class MockServiceWithStore : AbstractPrivateNotificationService() {
+ override val store = BrowserStore(
+ BrowserState(
+ locale = null,
+ ),
+ )
+ override val notificationsDelegate: NotificationsDelegate = mock()
+
+ override fun NotificationCompat.Builder.buildNotification() = Unit
+ override fun notifyLocaleChanged() {
+ // NOOP
+ }
+
+ override fun ignoreTaskActions(): List<String> = mock()
+ override fun ignoreTaskComponentClasses(): List<String> = mock()
+ }
+
+ private fun attachContext(service: Service) {
+ Mockito.doReturn(preferences).`when`(service).getSharedPreferences(anyString(), anyInt())
+ Mockito.doReturn(notificationManager).`when`(service).getSystemService<NotificationManager>()
+ Mockito.doReturn("").`when`(service).getString(anyInt())
+ Mockito.doReturn("").`when`(service).packageName
+ Mockito.doReturn(testContext.resources).`when`(service).resources
+ Mockito.doReturn(testContext.applicationInfo).`when`(service).applicationInfo
+ }
+}
diff --git a/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeatureTest.kt b/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeatureTest.kt
new file mode 100644
index 0000000000..8fa4015870
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/test/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeatureTest.kt
@@ -0,0 +1,133 @@
+/* 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 mozilla.components.feature.privatemode.notification
+
+import android.content.Context
+import android.content.Intent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import mozilla.components.browser.state.action.CustomTabListAction
+import mozilla.components.browser.state.action.TabListAction
+import mozilla.components.browser.state.state.createCustomTab
+import mozilla.components.browser.state.state.createTab
+import mozilla.components.browser.state.store.BrowserStore
+import mozilla.components.support.test.any
+import mozilla.components.support.test.argumentCaptor
+import mozilla.components.support.test.mock
+import mozilla.components.support.test.robolectric.testContext
+import mozilla.components.support.test.rule.MainCoroutineRule
+import mozilla.components.support.test.rule.runTestOnMain
+import mozilla.components.support.test.whenever
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
+class PrivateNotificationFeatureTest {
+
+ @get:Rule
+ val coroutinesTestRule = MainCoroutineRule()
+
+ private lateinit var context: Context
+ private lateinit var store: BrowserStore
+ private lateinit var feature: PrivateNotificationFeature<AbstractPrivateNotificationService>
+
+ @Before
+ fun setup() {
+ context = mock()
+ whenever(context.applicationContext).thenReturn(context)
+ whenever(context.packageName).thenReturn(testContext.packageName)
+
+ store = BrowserStore()
+
+ feature = PrivateNotificationFeature(context, store, AbstractPrivateNotificationService::class)
+ }
+
+ @Test
+ fun `service should be started if pre-existing private session is present`() = runTest(StandardTestDispatcher()) {
+ val privateSession = createTab("https://firefox.com", private = true)
+ val intent = argumentCaptor<Intent>()
+
+ store.dispatch(TabListAction.AddTabAction(privateSession)).join()
+
+ feature.start()
+ runCurrent()
+ verify(context, times(1)).startService(intent.capture())
+
+ val expected = Intent(testContext, AbstractPrivateNotificationService::class.java)
+ assertEquals(expected.component, intent.value.component)
+ assertTrue(expected.filterEquals(intent.value))
+ }
+
+ @Test
+ fun `service should be started when private session is added`() = runTestOnMain {
+ val privateSession = createTab("https://firefox.com", private = true)
+
+ feature.start()
+ verify(context, never()).startService(any())
+
+ store.dispatch(TabListAction.AddTabAction(privateSession)).join()
+ verify(context, times(1)).startService(any())
+ Unit
+ }
+
+ @Test
+ fun `service should not be started multiple times`() = runTestOnMain {
+ val privateSession1 = createTab("https://firefox.com", private = true)
+ val privateSession2 = createTab("https://mozilla.org", private = true)
+
+ feature.start()
+
+ store.dispatch(TabListAction.AddTabAction(privateSession1)).join()
+ store.dispatch(TabListAction.AddTabAction(privateSession2)).join()
+
+ verify(context, times(1)).startService(any())
+ Unit
+ }
+
+ @Test
+ fun `notification service should not be started when normal sessions are added`() = runTestOnMain {
+ val normalSession = createTab("https://firefox.com")
+ val customSession = createCustomTab("https://firefox.com")
+
+ feature.start()
+ verify(context, never()).startService(any())
+
+ store.dispatch(TabListAction.AddTabAction(normalSession)).join()
+ verify(context, never()).startService(any())
+
+ store.dispatch(CustomTabListAction.AddCustomTabAction(customSession)).join()
+ verify(context, never()).startService(any())
+ Unit
+ }
+
+ @Test
+ fun `notification service should not be started when custom sessions are added`() = runTestOnMain {
+ val privateCustomSession = createCustomTab("https://firefox.com").let {
+ it.copy(content = it.content.copy(private = true))
+ }
+ val customSession = createCustomTab("https://firefox.com")
+
+ feature.start()
+ verify(context, never()).startService(any())
+
+ store.dispatch(CustomTabListAction.AddCustomTabAction(privateCustomSession)).join()
+ verify(context, never()).startService(any())
+
+ store.dispatch(CustomTabListAction.AddCustomTabAction(customSession)).join()
+ verify(context, never()).startService(any())
+ Unit
+ }
+}
diff --git a/mobile/android/android-components/components/feature/privatemode/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/mobile/android/android-components/components/feature/privatemode/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000000..cf1c399ea8
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1,2 @@
+mock-maker-inline
+// This allows mocking final classes (classes are final by default in Kotlin)
diff --git a/mobile/android/android-components/components/feature/privatemode/src/test/resources/robolectric.properties b/mobile/android/android-components/components/feature/privatemode/src/test/resources/robolectric.properties
new file mode 100644
index 0000000000..932b01b9eb
--- /dev/null
+++ b/mobile/android/android-components/components/feature/privatemode/src/test/resources/robolectric.properties
@@ -0,0 +1 @@
+sdk=28