diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index a5007b6f0..c326c89d7 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -48,6 +48,7 @@ import org.mozilla.fenix.components.metrics.BreadcrumbsRecorder import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.exceptions.ExceptionsFragmentDirections import org.mozilla.fenix.ext.alreadyOnDestination +import org.mozilla.fenix.ext.checkAndUpdateScreenshotPermission import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.settings @@ -116,6 +117,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity() { components.publicSuffixList.prefetch() setupThemeAndBrowsingMode(getModeFromIntentOrLastKnown(intent)) + checkAndUpdateScreenshotPermission(settings()) setContentView(R.layout.activity_home) // Must be after we set the content view diff --git a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt index 7dd2b3dce..246e77113 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.ext import android.app.Activity import android.view.View import android.view.WindowManager +import org.mozilla.fenix.utils.Settings /** * Attempts to call immersive mode using the View to hide the status bar and navigation buttons. @@ -22,3 +23,19 @@ fun Activity.enterToImmersiveMode() { or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) } + +/** + * Prevents or allows screenshots from being taken in private mode based on the user preferences. + * + * The default setting is set to true (screenshots are allowed to be taken in private mode), as + * described in #2768 + */ +fun Activity.checkAndUpdateScreenshotPermission(settings: Settings) { + if (!settings.allowScreenshotsInPrivateMode && + settings.lastKnownMode.isPrivate + ) { + window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/PrivateBrowsingFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/PrivateBrowsingFragment.kt index 05355f6d3..ff1dc9b07 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/PrivateBrowsingFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/PrivateBrowsingFragment.kt @@ -11,8 +11,10 @@ import androidx.preference.SwitchPreference import org.mozilla.fenix.R import org.mozilla.fenix.components.PrivateShortcutCreateManager import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.ext.checkAndUpdateScreenshotPermission import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.metrics +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar /** @@ -41,5 +43,15 @@ class PrivateBrowsingFragment : PreferenceFragmentCompat() { findPreference(getPreferenceKey(R.string.pref_key_open_links_in_a_private_tab))?.apply { onPreferenceChangeListener = SharedPreferenceUpdater() } + + findPreference(getPreferenceKey + (R.string.pref_key_allow_screenshots_in_private_mode))?.apply { + onPreferenceChangeListener = object : SharedPreferenceUpdater() { + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + return super.onPreferenceChange(preference, newValue).also { + requireActivity().checkAndUpdateScreenshotPermission(requireActivity().settings()) } + } + } + } } } diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index 73b1de499..5b15f81e6 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -132,6 +132,11 @@ class Settings private constructor( default = false ) + var allowScreenshotsInPrivateMode by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_allow_screenshots_in_private_mode), + default = true + ) + var defaultSearchEngineName by stringPreference( appContext.getPreferenceKey(R.string.pref_key_search_engine), default = "" diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 8f7785775..c4c9b44ea 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -142,6 +142,7 @@ pref_key_open_links_in_a_private_tab pref_key_open_links_in_external_app + pref_key_allow_screenshots_in_private_mode pref_key_bounce_quick_action diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ac2b5688..5acb0047b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -203,6 +203,8 @@ Private browsing Open links in a private tab + + Allow screenshots in private browsing Add private browsing shortcut diff --git a/app/src/main/res/xml/private_browsing_preferences.xml b/app/src/main/res/xml/private_browsing_preferences.xml index 3f6be2234..6c43eefb9 100644 --- a/app/src/main/res/xml/private_browsing_preferences.xml +++ b/app/src/main/res/xml/private_browsing_preferences.xml @@ -13,4 +13,9 @@ android:key="@string/pref_key_open_links_in_a_private_tab" android:title="@string/preferences_open_links_in_a_private_tab" app:iconSpaceReserved="false" /> + diff --git a/app/src/test/java/org/mozilla/fenix/ext/ActivityTest.kt b/app/src/test/java/org/mozilla/fenix/ext/ActivityTest.kt index 5e22803e4..dfb2816a3 100644 --- a/app/src/test/java/org/mozilla/fenix/ext/ActivityTest.kt +++ b/app/src/test/java/org/mozilla/fenix/ext/ActivityTest.kt @@ -7,12 +7,15 @@ package org.mozilla.fenix.ext import android.app.Activity import android.view.View import android.view.WindowManager +import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith -import org.robolectric.Robolectric +import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.robolectric.Robolectric import org.robolectric.Shadows.shadowOf @RunWith(FenixRobolectricTestRunner::class) @@ -39,4 +42,67 @@ class ActivityTest { for (f in flags) assertEquals(f, window.decorView.systemUiVisibility and f) assertTrue(shadowOf(window).getFlag(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)) } + + @Test + fun `testCheckAndUpdateScreenshotPermission adds flag in private mode when screenshots are not allowed `() { + // given + val activity = Robolectric.buildActivity(Activity::class.java).create().get() + val window = activity.window + testContext.settings().lastKnownMode = BrowsingMode.Private + testContext.settings().allowScreenshotsInPrivateMode = false + + // when + activity.checkAndUpdateScreenshotPermission(activity.settings()) + + // then + assertTrue(shadowOf(window).getFlag(WindowManager.LayoutParams.FLAG_SECURE)) + } + + @Test + fun `testCheckAndUpdateScreenshotPermission removes flag in private mode when screenshots are allowed `() { + // given + val activity = Robolectric.buildActivity(Activity::class.java).create().get() + val window = activity.window + window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + testContext.settings().lastKnownMode = BrowsingMode.Private + testContext.settings().allowScreenshotsInPrivateMode = true + + // when + activity.checkAndUpdateScreenshotPermission(activity.settings()) + + // then + assertFalse(shadowOf(window).getFlag(WindowManager.LayoutParams.FLAG_SECURE)) + } + + @Test + fun `testCheckAndUpdateScreenshotPermission removes flag in normal mode when screenshots are allowed `() { + // given + val activity = Robolectric.buildActivity(Activity::class.java).create().get() + val window = activity.window + window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + testContext.settings().lastKnownMode = BrowsingMode.Normal + testContext.settings().allowScreenshotsInPrivateMode = true + + // when + activity.checkAndUpdateScreenshotPermission(activity.settings()) + + // then + assertFalse(shadowOf(window).getFlag(WindowManager.LayoutParams.FLAG_SECURE)) + } + + @Test + fun `testCheckAndUpdateScreenshotPermission removes flag when in normal mode screenshots are not allowed `() { + // given + val activity = Robolectric.buildActivity(Activity::class.java).create().get() + val window = activity.window + window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + testContext.settings().lastKnownMode = BrowsingMode.Normal + testContext.settings().allowScreenshotsInPrivateMode = false + + // when + activity.checkAndUpdateScreenshotPermission(activity.settings()) + + // then + assertFalse(shadowOf(window).getFlag(WindowManager.LayoutParams.FLAG_SECURE)) + } }