setting to enable screenshot protection
This commit is contained in:
+17
@@ -107,6 +107,23 @@ class EngineSettingsReplicationService
|
||||
},
|
||||
);
|
||||
|
||||
ref.listen(
|
||||
fireImmediately: true,
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
(settings) => settings.screenshotProtectionEnabled,
|
||||
),
|
||||
(previous, next) async {
|
||||
await _service.setScreenshotProtectionEnabled(next);
|
||||
},
|
||||
onError: (error, stackTrace) {
|
||||
logger.e(
|
||||
'Error listening to screenshotProtectionEnabled',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
ref.listen(
|
||||
fireImmediately: true,
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ final class EngineSettingsReplicationServiceProvider
|
||||
}
|
||||
|
||||
String _$engineSettingsReplicationServiceHash() =>
|
||||
r'71b611a99af83187e392d16288cec280ef44269f';
|
||||
r'8f37476c9beecd6cc70a07b8cd3a51864b077176';
|
||||
|
||||
abstract class _$EngineSettingsReplicationService extends $Notifier<void> {
|
||||
void build();
|
||||
|
||||
+31
@@ -144,6 +144,7 @@ class _PrivacySignalsSection extends StatelessWidget {
|
||||
children: [
|
||||
SettingSection(name: 'Privacy Signals & Modes'),
|
||||
_IncognitoModeSection(),
|
||||
_ScreenshotProtectionTile(),
|
||||
_GlobalPrivacyControlTile(),
|
||||
],
|
||||
);
|
||||
@@ -452,6 +453,36 @@ class _GlobalPrivacyControlTile extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _ScreenshotProtectionTile extends HookConsumerWidget {
|
||||
const _ScreenshotProtectionTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final enabled = ref.watch(
|
||||
generalSettingsWithDefaultsProvider.select(
|
||||
(s) => s.screenshotProtectionEnabled,
|
||||
),
|
||||
);
|
||||
|
||||
return SwitchListTile.adaptive(
|
||||
title: const Text('Screenshot protection'),
|
||||
subtitle: const Text(
|
||||
'Blocks screenshots and screen recordings for this app on Android.',
|
||||
),
|
||||
secondary: const Icon(MdiIcons.cameraOff),
|
||||
value: enabled,
|
||||
onChanged: (value) async {
|
||||
await ref
|
||||
.read(saveGeneralSettingsControllerProvider.notifier)
|
||||
.save(
|
||||
(currentSettings) => currentSettings.copyWith
|
||||
.screenshotProtectionEnabled(value),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _HttpsOnlyModeSection extends HookConsumerWidget {
|
||||
const _HttpsOnlyModeSection();
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ class GeneralSettings with FastEquatable {
|
||||
final bool enableReadability;
|
||||
final bool enforceReadability;
|
||||
final Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit;
|
||||
final bool screenshotProtectionEnabled;
|
||||
@BangKeyConverter()
|
||||
final BangKey? defaultSearchProvider;
|
||||
final SearchSuggestionProviders defaultSearchSuggestionsProvider;
|
||||
@@ -131,6 +132,7 @@ class GeneralSettings with FastEquatable {
|
||||
required this.enableReadability,
|
||||
required this.enforceReadability,
|
||||
required this.deleteBrowsingDataOnQuit,
|
||||
required this.screenshotProtectionEnabled,
|
||||
required this.defaultSearchProvider,
|
||||
required this.defaultSearchSuggestionsProvider,
|
||||
required this.createChildTabsOption,
|
||||
@@ -185,6 +187,7 @@ class GeneralSettings with FastEquatable {
|
||||
bool? enableReadability,
|
||||
bool? enforceReadability,
|
||||
this.deleteBrowsingDataOnQuit,
|
||||
bool? screenshotProtectionEnabled,
|
||||
BangKey? defaultSearchProvider,
|
||||
SearchSuggestionProviders? defaultSearchSuggestionsProvider,
|
||||
bool? createChildTabsOption,
|
||||
@@ -233,9 +236,10 @@ class GeneralSettings with FastEquatable {
|
||||
uiScaleFactor = uiScaleFactor ?? defaultUiScaleFactor,
|
||||
disableAnimations = disableAnimations ?? false,
|
||||
showModalBarrier = showModalBarrier ?? true,
|
||||
enableReadability = enableReadability ?? true,
|
||||
enforceReadability = enforceReadability ?? false,
|
||||
defaultSearchProvider = defaultSearchProvider ?? _fallbackSearchProvider,
|
||||
enableReadability = enableReadability ?? true,
|
||||
enforceReadability = enforceReadability ?? false,
|
||||
screenshotProtectionEnabled = screenshotProtectionEnabled ?? false,
|
||||
defaultSearchProvider = defaultSearchProvider ?? _fallbackSearchProvider,
|
||||
defaultSearchSuggestionsProvider =
|
||||
defaultSearchSuggestionsProvider ?? _fallbackAutocompleteProvider,
|
||||
createChildTabsOption = createChildTabsOption ?? false,
|
||||
@@ -320,6 +324,7 @@ class GeneralSettings with FastEquatable {
|
||||
enableReadability,
|
||||
enforceReadability,
|
||||
deleteBrowsingDataOnQuit,
|
||||
screenshotProtectionEnabled,
|
||||
defaultSearchProvider,
|
||||
defaultSearchSuggestionsProvider,
|
||||
createChildTabsOption,
|
||||
|
||||
@@ -23,6 +23,8 @@ abstract class _$GeneralSettingsCWProxy {
|
||||
Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit,
|
||||
);
|
||||
|
||||
GeneralSettings screenshotProtectionEnabled(bool screenshotProtectionEnabled);
|
||||
|
||||
GeneralSettings defaultSearchProvider(BangKey? defaultSearchProvider);
|
||||
|
||||
GeneralSettings defaultSearchSuggestionsProvider(
|
||||
@@ -144,6 +146,7 @@ abstract class _$GeneralSettingsCWProxy {
|
||||
bool enableReadability,
|
||||
bool enforceReadability,
|
||||
Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit,
|
||||
bool screenshotProtectionEnabled,
|
||||
BangKey? defaultSearchProvider,
|
||||
SearchSuggestionProviders defaultSearchSuggestionsProvider,
|
||||
bool createChildTabsOption,
|
||||
@@ -226,6 +229,11 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
||||
Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit,
|
||||
) => call(deleteBrowsingDataOnQuit: deleteBrowsingDataOnQuit);
|
||||
|
||||
@override
|
||||
GeneralSettings screenshotProtectionEnabled(
|
||||
bool screenshotProtectionEnabled,
|
||||
) => call(screenshotProtectionEnabled: screenshotProtectionEnabled);
|
||||
|
||||
@override
|
||||
GeneralSettings defaultSearchProvider(BangKey? defaultSearchProvider) =>
|
||||
call(defaultSearchProvider: defaultSearchProvider);
|
||||
@@ -431,6 +439,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
||||
Object? enableReadability = const $CopyWithPlaceholder(),
|
||||
Object? enforceReadability = const $CopyWithPlaceholder(),
|
||||
Object? deleteBrowsingDataOnQuit = const $CopyWithPlaceholder(),
|
||||
Object? screenshotProtectionEnabled = const $CopyWithPlaceholder(),
|
||||
Object? defaultSearchProvider = const $CopyWithPlaceholder(),
|
||||
Object? defaultSearchSuggestionsProvider = const $CopyWithPlaceholder(),
|
||||
Object? createChildTabsOption = const $CopyWithPlaceholder(),
|
||||
@@ -516,6 +525,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
||||
? _value.deleteBrowsingDataOnQuit
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: deleteBrowsingDataOnQuit as Set<DeleteBrowsingDataType>?,
|
||||
screenshotProtectionEnabled:
|
||||
screenshotProtectionEnabled == const $CopyWithPlaceholder() ||
|
||||
screenshotProtectionEnabled == null
|
||||
? _value.screenshotProtectionEnabled
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: screenshotProtectionEnabled as bool,
|
||||
defaultSearchProvider:
|
||||
defaultSearchProvider == const $CopyWithPlaceholder()
|
||||
? _value.defaultSearchProvider
|
||||
@@ -805,6 +820,7 @@ GeneralSettings _$GeneralSettingsFromJson(
|
||||
deleteBrowsingDataOnQuit: (json['deleteBrowsingDataOnQuit'] as List<dynamic>?)
|
||||
?.map((e) => $enumDecode(_$DeleteBrowsingDataTypeEnumMap, e))
|
||||
.toSet(),
|
||||
screenshotProtectionEnabled: json['screenshotProtectionEnabled'] as bool?,
|
||||
defaultSearchProvider: const BangKeyConverter().fromJson(
|
||||
json['defaultSearchProvider'] as String?,
|
||||
),
|
||||
@@ -908,6 +924,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
|
||||
'deleteBrowsingDataOnQuit': instance.deleteBrowsingDataOnQuit
|
||||
?.map((e) => _$DeleteBrowsingDataTypeEnumMap[e]!)
|
||||
.toList(),
|
||||
'screenshotProtectionEnabled': instance.screenshotProtectionEnabled,
|
||||
'defaultSearchProvider': const BangKeyConverter().toJson(
|
||||
instance.defaultSearchProvider,
|
||||
),
|
||||
|
||||
@@ -71,6 +71,8 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
||||
'deleteBrowsingDataOnQuit': settings['deleteBrowsingDataOnQuit']
|
||||
?.readAs(DriftSqlType.string, db.typeMapping)
|
||||
.mapNotNull(jsonDecode),
|
||||
'screenshotProtectionEnabled': settings['screenshotProtectionEnabled']
|
||||
?.readAs(DriftSqlType.bool, db.typeMapping),
|
||||
'defaultSearchProvider': settings['defaultSearchProvider']?.readAs(
|
||||
DriftSqlType.string,
|
||||
db.typeMapping,
|
||||
|
||||
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
|
||||
}
|
||||
|
||||
String _$generalSettingsRepositoryHash() =>
|
||||
r'9d34ea4b802d2d1b1c9543f41ad5fdf28f279e06';
|
||||
r'f75d5cb1963c16404f5fd02db0097b72451717eb';
|
||||
|
||||
abstract class _$GeneralSettingsRepository
|
||||
extends $StreamNotifier<GeneralSettings> {
|
||||
|
||||
+24
@@ -16,6 +16,7 @@ import android.os.Environment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager.LayoutParams.FLAG_SECURE
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -34,6 +35,7 @@ import eu.weblibre.flutter_mozilla_components.integration.ReaderViewIntegration
|
||||
import eu.weblibre.flutter_mozilla_components.activities.ExternalAppBrowserActivity
|
||||
import eu.weblibre.flutter_mozilla_components.services.DownloadService
|
||||
import io.flutter.Log
|
||||
import mozilla.components.browser.state.selector.findCustomTabOrSelectedTab
|
||||
import mozilla.components.browser.state.state.WebExtensionState
|
||||
import mozilla.components.browser.thumbnails.BrowserThumbnails
|
||||
import mozilla.components.concept.engine.EngineView
|
||||
@@ -150,6 +152,18 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
||||
private lateinit var requestSitePermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||
private lateinit var requestPromptsPermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||
|
||||
private fun updateSecureWindowState() {
|
||||
val tab = components.core.store.state.findCustomTabOrSelectedTab(sessionId)
|
||||
val shouldSecure =
|
||||
GlobalComponents.screenshotProtectionEnabled || tab?.content?.private == true
|
||||
|
||||
if (shouldSecure) {
|
||||
requireActivity().window.addFlags(FLAG_SECURE)
|
||||
} else {
|
||||
requireActivity().window.clearFlags(FLAG_SECURE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -268,6 +282,10 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
||||
GlobalComponents.onPullToRefreshEnabledChanged = { enabled ->
|
||||
_binding?.swipeToRefresh?.isEnabled = enabled
|
||||
}
|
||||
GlobalComponents.onScreenshotProtectionEnabledChanged = {
|
||||
updateSecureWindowState()
|
||||
}
|
||||
updateSecureWindowState()
|
||||
|
||||
shareResourceFeature.set(
|
||||
ShareResourceFeature(
|
||||
@@ -461,6 +479,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
||||
window = requireActivity().window,
|
||||
store = components.core.store,
|
||||
customTabId = sessionId,
|
||||
isSecure = { session ->
|
||||
session.content.private ||
|
||||
GlobalComponents.screenshotProtectionEnabled
|
||||
},
|
||||
clearFlagOnStop = false,
|
||||
),
|
||||
owner = this,
|
||||
view = binding.root,
|
||||
@@ -663,6 +686,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
||||
browserHandlingScrollFeature = null
|
||||
|
||||
GlobalComponents.onPullToRefreshEnabledChanged = null
|
||||
GlobalComponents.onScreenshotProtectionEnabledChanged = null
|
||||
val engineView = fragmentEngineView
|
||||
engineView?.setActivityContext(null)
|
||||
if (components.activeEngineView == engineView) {
|
||||
|
||||
+8
@@ -75,6 +75,14 @@ object GlobalComponents {
|
||||
|
||||
var onPullToRefreshEnabledChanged: ((Boolean) -> Unit)? = null
|
||||
|
||||
var screenshotProtectionEnabled: Boolean = false
|
||||
set(value) {
|
||||
field = value
|
||||
onScreenshotProtectionEnabledChanged?.invoke(value)
|
||||
}
|
||||
|
||||
var onScreenshotProtectionEnabledChanged: ((Boolean) -> Unit)? = null
|
||||
|
||||
// Viewport events for keyboard visibility notifications
|
||||
var viewportEvents: GeckoViewportEvents? = null
|
||||
|
||||
|
||||
+4
@@ -419,6 +419,10 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
|
||||
GlobalComponents.pullToRefreshEnabled = enabled
|
||||
}
|
||||
|
||||
override fun setScreenshotProtectionEnabled(enabled: Boolean) {
|
||||
GlobalComponents.screenshotProtectionEnabled = enabled
|
||||
}
|
||||
|
||||
override fun setAppLinksMode(mode: AppLinksMode) {
|
||||
val context = components.profileApplicationContext
|
||||
val prefKey = context.getString(R.string.pref_key_open_links_in_apps)
|
||||
|
||||
+19
@@ -6752,6 +6752,7 @@ interface GeckoSyncApi {
|
||||
interface GeckoEngineSettingsApi {
|
||||
fun setDefaultSettings(settings: GeckoEngineSettings)
|
||||
fun updateRuntimeSettings(settings: GeckoEngineSettings)
|
||||
fun setScreenshotProtectionEnabled(enabled: Boolean)
|
||||
fun setPullToRefreshEnabled(enabled: Boolean)
|
||||
/**
|
||||
* Sets the app links mode preference (stored in SharedPreferences).
|
||||
@@ -6811,6 +6812,24 @@ interface GeckoEngineSettingsApi {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoEngineSettingsApi.setScreenshotProtectionEnabled$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val enabledArg = args[0] as Boolean
|
||||
val wrapped: List<Any?> = try {
|
||||
api.setScreenshotProtectionEnabled(enabledArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
GeckoPigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoEngineSettingsApi.setPullToRefreshEnabled$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
|
||||
@@ -189,6 +189,10 @@ class GeckoEngineSettingsService {
|
||||
return _api.updateRuntimeSettings(GeckoEngineSettings(lnaEnabled: state));
|
||||
}
|
||||
|
||||
Future<void> setScreenshotProtectionEnabled(bool enabled) {
|
||||
return _api.setScreenshotProtectionEnabled(enabled);
|
||||
}
|
||||
|
||||
Future<void> setPullToRefreshEnabled(bool enabled) {
|
||||
return _api.setPullToRefreshEnabled(enabled);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1494,6 +1494,7 @@ abstract class GeckoSyncApi {
|
||||
abstract class GeckoEngineSettingsApi {
|
||||
void setDefaultSettings(GeckoEngineSettings settings);
|
||||
void updateRuntimeSettings(GeckoEngineSettings settings);
|
||||
void setScreenshotProtectionEnabled(bool enabled);
|
||||
void setPullToRefreshEnabled(bool enabled);
|
||||
|
||||
/// Sets the app links mode preference (stored in SharedPreferences).
|
||||
|
||||
Reference in New Issue
Block a user