From 68a5b44663271e2dea0a1f65afd57e4fc0ecf907 Mon Sep 17 00:00:00 2001 From: Mihai Eduard Badea Date: Fri, 3 Apr 2020 12:19:39 +0300 Subject: [PATCH] [fenix] For https://github.com/mozilla-mobile/fenix/issues/2768 - Prevent screenshots in private mode Added a new option in Private browsing menu to allow or prevent screenshots from being taken while in private mode by adding or removing the FLAG_SECURE flag from the home activity's window. This method is called whenever the activity is initialized to account for the browsing mode being changed and whenever the setting from the Private browsing menu is changed. The setting is by default set to true (screenshots are allowed to be taken) --- .../java/org/mozilla/fenix/HomeActivity.kt | 2 + .../java/org/mozilla/fenix/ext/Activity.kt | 17 +++++ .../fenix/settings/PrivateBrowsingFragment.kt | 12 ++++ .../java/org/mozilla/fenix/utils/Settings.kt | 5 ++ app/src/main/res/values/preference_keys.xml | 1 + app/src/main/res/values/strings.xml | 2 + .../res/xml/private_browsing_preferences.xml | 5 ++ .../org/mozilla/fenix/ext/ActivityTest.kt | 68 ++++++++++++++++++- 8 files changed, 111 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index a5007b6f08..c326c89d77 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 7dd2b3dcec..246e771135 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 05355f6d3d..ff1dc9b076 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 73b1de499d..5b15f81e65 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 8f77857750..c4c9b44ea1 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 0ac2b56886..5acb0047be 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 3f6be22348..6c43eefb96 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 5e22803e4a..dfb2816a3e 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)) + } }