costom tabs setting
This commit is contained in:
+10
-1
@@ -45,7 +45,12 @@ class NativeIntentGatekeeperReplicator
|
|||||||
Future<void>? _pendingAllowSync;
|
Future<void>? _pendingAllowSync;
|
||||||
|
|
||||||
Future<void> _push(
|
Future<void> _push(
|
||||||
({bool enabled, Map<String, IntentSourcePolicy> policies}) config,
|
({
|
||||||
|
bool enabled,
|
||||||
|
Map<String, IntentSourcePolicy> policies,
|
||||||
|
bool customTabsEnabled,
|
||||||
|
})
|
||||||
|
config,
|
||||||
) async {
|
) async {
|
||||||
final blocked = config.policies.entries
|
final blocked = config.policies.entries
|
||||||
.where((entry) => entry.value == IntentSourcePolicy.block)
|
.where((entry) => entry.value == IntentSourcePolicy.block)
|
||||||
@@ -54,6 +59,7 @@ class NativeIntentGatekeeperReplicator
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await _api.setConfig(config.enabled, blocked);
|
await _api.setConfig(config.enabled, blocked);
|
||||||
|
await _api.setCustomTabsEnabled(config.customTabsEnabled);
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
logger.e(
|
logger.e(
|
||||||
'Failed to replicate intent gatekeeper config to native',
|
'Failed to replicate intent gatekeeper config to native',
|
||||||
@@ -116,6 +122,7 @@ class NativeIntentGatekeeperReplicator
|
|||||||
(settings) => EquatableValue((
|
(settings) => EquatableValue((
|
||||||
enabled: settings.blockExternalAppsEnabled,
|
enabled: settings.blockExternalAppsEnabled,
|
||||||
policies: settings.externalAppIntentPolicies,
|
policies: settings.externalAppIntentPolicies,
|
||||||
|
customTabsEnabled: settings.customTabsEnabled,
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
fireImmediately: true,
|
fireImmediately: true,
|
||||||
@@ -125,6 +132,7 @@ class NativeIntentGatekeeperReplicator
|
|||||||
|
|
||||||
if (previous != null &&
|
if (previous != null &&
|
||||||
previous.enabled == next.enabled &&
|
previous.enabled == next.enabled &&
|
||||||
|
previous.customTabsEnabled == next.customTabsEnabled &&
|
||||||
const DeepCollectionEquality.unordered().equals(
|
const DeepCollectionEquality.unordered().equals(
|
||||||
previous.policies,
|
previous.policies,
|
||||||
next.policies,
|
next.policies,
|
||||||
@@ -139,6 +147,7 @@ class NativeIntentGatekeeperReplicator
|
|||||||
await _push((
|
await _push((
|
||||||
enabled: settings.blockExternalAppsEnabled,
|
enabled: settings.blockExternalAppsEnabled,
|
||||||
policies: settings.externalAppIntentPolicies,
|
policies: settings.externalAppIntentPolicies,
|
||||||
|
customTabsEnabled: settings.customTabsEnabled,
|
||||||
));
|
));
|
||||||
}());
|
}());
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ final class NativeIntentGatekeeperReplicatorProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$nativeIntentGatekeeperReplicatorHash() =>
|
String _$nativeIntentGatekeeperReplicatorHash() =>
|
||||||
r'bb2e2a252143879e558d513f9c48f3e66513baa9';
|
r'1425d7d540d872d82a2d97e0a9fff6a4f6d9ae7b';
|
||||||
|
|
||||||
/// Mirrors the Flutter-side block list to the native side so the
|
/// Mirrors the Flutter-side block list to the native side so the
|
||||||
/// `IntentReceiverActivity` can reject intents without launching Flutter.
|
/// `IntentReceiverActivity` can reject intents without launching Flutter.
|
||||||
|
|||||||
@@ -144,6 +144,20 @@ const List<SettingsSectionDefinition> browsingSettingsSections = [
|
|||||||
keywords: ['intents'],
|
keywords: ['intents'],
|
||||||
child: _ExternalLinkHandlingSection(),
|
child: _ExternalLinkHandlingSection(),
|
||||||
),
|
),
|
||||||
|
SettingsEntryDefinition(
|
||||||
|
title: 'Custom Tabs',
|
||||||
|
subtitle:
|
||||||
|
'Let other apps open links in a lightweight in-app tab, instead '
|
||||||
|
'of the main browser',
|
||||||
|
keywords: [
|
||||||
|
'custom tabs',
|
||||||
|
'in-app browser',
|
||||||
|
'chrome custom tabs',
|
||||||
|
'external app',
|
||||||
|
'share',
|
||||||
|
],
|
||||||
|
child: _CustomTabsTile(),
|
||||||
|
),
|
||||||
SettingsEntryDefinition(
|
SettingsEntryDefinition(
|
||||||
title: 'URL Cleaner',
|
title: 'URL Cleaner',
|
||||||
subtitle: 'Tracking removal rules and catalog updates',
|
subtitle: 'Tracking removal rules and catalog updates',
|
||||||
@@ -821,6 +835,35 @@ class _PullToRefreshTile extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _CustomTabsTile extends HookConsumerWidget {
|
||||||
|
const _CustomTabsTile();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final customTabsEnabled = ref.watch(
|
||||||
|
generalSettingsWithDefaultsProvider.select((s) => s.customTabsEnabled),
|
||||||
|
);
|
||||||
|
|
||||||
|
return SwitchListTile.adaptive(
|
||||||
|
title: const Text('Custom Tabs'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Let other apps open links in a lightweight in-app tab. When off, '
|
||||||
|
'these links and shared URLs open as normal tabs in the main browser.',
|
||||||
|
),
|
||||||
|
secondary: const Icon(Icons.web_asset),
|
||||||
|
value: customTabsEnabled,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(saveGeneralSettingsControllerProvider.notifier)
|
||||||
|
.save(
|
||||||
|
(currentSettings) =>
|
||||||
|
currentSettings.copyWith.customTabsEnabled(value),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _DoubleBackCloseTabTile extends HookConsumerWidget {
|
class _DoubleBackCloseTabTile extends HookConsumerWidget {
|
||||||
const _DoubleBackCloseTabTile();
|
const _DoubleBackCloseTabTile();
|
||||||
|
|
||||||
|
|||||||
@@ -196,6 +196,12 @@ class GeneralSettings with FastEquatable {
|
|||||||
final bool blockExternalAppsEnabled;
|
final bool blockExternalAppsEnabled;
|
||||||
final Map<String, IntentSourcePolicy> externalAppIntentPolicies;
|
final Map<String, IntentSourcePolicy> externalAppIntentPolicies;
|
||||||
|
|
||||||
|
/// Whether external Custom Tab intents (and URLs shared into WebLibre) open
|
||||||
|
/// in a lightweight custom-tab activity. When false, they open as normal
|
||||||
|
/// tabs in the main browser instead. Read natively by `IntentReceiverActivity`
|
||||||
|
/// via the intent gatekeeper prefs bridge. Defaults to true.
|
||||||
|
final bool customTabsEnabled;
|
||||||
|
|
||||||
/// Whether the local search index (`history` table populated via tab→
|
/// Whether the local search index (`history` table populated via tab→
|
||||||
/// history triggers) is active. When false, the SQL trigger guard returns
|
/// history triggers) is active. When false, the SQL trigger guard returns
|
||||||
/// without writing; existing rows stay until the user clears them.
|
/// without writing; existing rows stay until the user clears them.
|
||||||
@@ -289,6 +295,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
required this.allowNonManifestPwaInstall,
|
required this.allowNonManifestPwaInstall,
|
||||||
required this.blockExternalAppsEnabled,
|
required this.blockExternalAppsEnabled,
|
||||||
required this.externalAppIntentPolicies,
|
required this.externalAppIntentPolicies,
|
||||||
|
required this.customTabsEnabled,
|
||||||
required this.enableLocalSearchIndex,
|
required this.enableLocalSearchIndex,
|
||||||
required this.indexPrivateTabs,
|
required this.indexPrivateTabs,
|
||||||
required this.acceptSuggestionOnSubmit,
|
required this.acceptSuggestionOnSubmit,
|
||||||
@@ -356,6 +363,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
bool? allowNonManifestPwaInstall,
|
bool? allowNonManifestPwaInstall,
|
||||||
bool? blockExternalAppsEnabled,
|
bool? blockExternalAppsEnabled,
|
||||||
Map<String, IntentSourcePolicy>? externalAppIntentPolicies,
|
Map<String, IntentSourcePolicy>? externalAppIntentPolicies,
|
||||||
|
bool? customTabsEnabled,
|
||||||
bool? enableLocalSearchIndex,
|
bool? enableLocalSearchIndex,
|
||||||
bool? indexPrivateTabs,
|
bool? indexPrivateTabs,
|
||||||
bool? acceptSuggestionOnSubmit,
|
bool? acceptSuggestionOnSubmit,
|
||||||
@@ -433,6 +441,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
allowNonManifestPwaInstall = allowNonManifestPwaInstall ?? false,
|
allowNonManifestPwaInstall = allowNonManifestPwaInstall ?? false,
|
||||||
blockExternalAppsEnabled = blockExternalAppsEnabled ?? false,
|
blockExternalAppsEnabled = blockExternalAppsEnabled ?? false,
|
||||||
externalAppIntentPolicies = externalAppIntentPolicies ?? const {},
|
externalAppIntentPolicies = externalAppIntentPolicies ?? const {},
|
||||||
|
customTabsEnabled = customTabsEnabled ?? true,
|
||||||
enableLocalSearchIndex = enableLocalSearchIndex ?? true,
|
enableLocalSearchIndex = enableLocalSearchIndex ?? true,
|
||||||
indexPrivateTabs = indexPrivateTabs ?? false,
|
indexPrivateTabs = indexPrivateTabs ?? false,
|
||||||
acceptSuggestionOnSubmit = acceptSuggestionOnSubmit ?? false,
|
acceptSuggestionOnSubmit = acceptSuggestionOnSubmit ?? false,
|
||||||
@@ -574,6 +583,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
allowNonManifestPwaInstall,
|
allowNonManifestPwaInstall,
|
||||||
blockExternalAppsEnabled,
|
blockExternalAppsEnabled,
|
||||||
externalAppIntentPolicies,
|
externalAppIntentPolicies,
|
||||||
|
customTabsEnabled,
|
||||||
enableLocalSearchIndex,
|
enableLocalSearchIndex,
|
||||||
indexPrivateTabs,
|
indexPrivateTabs,
|
||||||
acceptSuggestionOnSubmit,
|
acceptSuggestionOnSubmit,
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
Map<String, IntentSourcePolicy> externalAppIntentPolicies,
|
Map<String, IntentSourcePolicy> externalAppIntentPolicies,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GeneralSettings customTabsEnabled(bool customTabsEnabled);
|
||||||
|
|
||||||
GeneralSettings enableLocalSearchIndex(bool enableLocalSearchIndex);
|
GeneralSettings enableLocalSearchIndex(bool enableLocalSearchIndex);
|
||||||
|
|
||||||
GeneralSettings indexPrivateTabs(bool indexPrivateTabs);
|
GeneralSettings indexPrivateTabs(bool indexPrivateTabs);
|
||||||
@@ -220,6 +222,7 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
bool allowNonManifestPwaInstall,
|
bool allowNonManifestPwaInstall,
|
||||||
bool blockExternalAppsEnabled,
|
bool blockExternalAppsEnabled,
|
||||||
Map<String, IntentSourcePolicy> externalAppIntentPolicies,
|
Map<String, IntentSourcePolicy> externalAppIntentPolicies,
|
||||||
|
bool customTabsEnabled,
|
||||||
bool enableLocalSearchIndex,
|
bool enableLocalSearchIndex,
|
||||||
bool indexPrivateTabs,
|
bool indexPrivateTabs,
|
||||||
bool acceptSuggestionOnSubmit,
|
bool acceptSuggestionOnSubmit,
|
||||||
@@ -483,6 +486,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Map<String, IntentSourcePolicy> externalAppIntentPolicies,
|
Map<String, IntentSourcePolicy> externalAppIntentPolicies,
|
||||||
) => call(externalAppIntentPolicies: externalAppIntentPolicies);
|
) => call(externalAppIntentPolicies: externalAppIntentPolicies);
|
||||||
|
|
||||||
|
@override
|
||||||
|
GeneralSettings customTabsEnabled(bool customTabsEnabled) =>
|
||||||
|
call(customTabsEnabled: customTabsEnabled);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
GeneralSettings enableLocalSearchIndex(bool enableLocalSearchIndex) =>
|
GeneralSettings enableLocalSearchIndex(bool enableLocalSearchIndex) =>
|
||||||
call(enableLocalSearchIndex: enableLocalSearchIndex);
|
call(enableLocalSearchIndex: enableLocalSearchIndex);
|
||||||
@@ -578,6 +585,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Object? allowNonManifestPwaInstall = const $CopyWithPlaceholder(),
|
Object? allowNonManifestPwaInstall = const $CopyWithPlaceholder(),
|
||||||
Object? blockExternalAppsEnabled = const $CopyWithPlaceholder(),
|
Object? blockExternalAppsEnabled = const $CopyWithPlaceholder(),
|
||||||
Object? externalAppIntentPolicies = const $CopyWithPlaceholder(),
|
Object? externalAppIntentPolicies = const $CopyWithPlaceholder(),
|
||||||
|
Object? customTabsEnabled = const $CopyWithPlaceholder(),
|
||||||
Object? enableLocalSearchIndex = const $CopyWithPlaceholder(),
|
Object? enableLocalSearchIndex = const $CopyWithPlaceholder(),
|
||||||
Object? indexPrivateTabs = const $CopyWithPlaceholder(),
|
Object? indexPrivateTabs = const $CopyWithPlaceholder(),
|
||||||
Object? acceptSuggestionOnSubmit = const $CopyWithPlaceholder(),
|
Object? acceptSuggestionOnSubmit = const $CopyWithPlaceholder(),
|
||||||
@@ -924,6 +932,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
? _value.externalAppIntentPolicies
|
? _value.externalAppIntentPolicies
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: externalAppIntentPolicies as Map<String, IntentSourcePolicy>,
|
: externalAppIntentPolicies as Map<String, IntentSourcePolicy>,
|
||||||
|
customTabsEnabled:
|
||||||
|
customTabsEnabled == const $CopyWithPlaceholder() ||
|
||||||
|
customTabsEnabled == null
|
||||||
|
? _value.customTabsEnabled
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: customTabsEnabled as bool,
|
||||||
enableLocalSearchIndex:
|
enableLocalSearchIndex:
|
||||||
enableLocalSearchIndex == const $CopyWithPlaceholder() ||
|
enableLocalSearchIndex == const $CopyWithPlaceholder() ||
|
||||||
enableLocalSearchIndex == null
|
enableLocalSearchIndex == null
|
||||||
@@ -1095,6 +1109,7 @@ GeneralSettings _$GeneralSettingsFromJson(
|
|||||||
(json['externalAppIntentPolicies'] as Map<String, dynamic>?)?.map(
|
(json['externalAppIntentPolicies'] as Map<String, dynamic>?)?.map(
|
||||||
(k, e) => MapEntry(k, $enumDecode(_$IntentSourcePolicyEnumMap, e)),
|
(k, e) => MapEntry(k, $enumDecode(_$IntentSourcePolicyEnumMap, e)),
|
||||||
),
|
),
|
||||||
|
customTabsEnabled: json['customTabsEnabled'] as bool?,
|
||||||
enableLocalSearchIndex: json['enableLocalSearchIndex'] as bool?,
|
enableLocalSearchIndex: json['enableLocalSearchIndex'] as bool?,
|
||||||
indexPrivateTabs: json['indexPrivateTabs'] as bool?,
|
indexPrivateTabs: json['indexPrivateTabs'] as bool?,
|
||||||
acceptSuggestionOnSubmit: json['acceptSuggestionOnSubmit'] as bool?,
|
acceptSuggestionOnSubmit: json['acceptSuggestionOnSubmit'] as bool?,
|
||||||
@@ -1180,6 +1195,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
|
|||||||
'externalAppIntentPolicies': instance.externalAppIntentPolicies.map(
|
'externalAppIntentPolicies': instance.externalAppIntentPolicies.map(
|
||||||
(k, e) => MapEntry(k, _$IntentSourcePolicyEnumMap[e]!),
|
(k, e) => MapEntry(k, _$IntentSourcePolicyEnumMap[e]!),
|
||||||
),
|
),
|
||||||
|
'customTabsEnabled': instance.customTabsEnabled,
|
||||||
'enableLocalSearchIndex': instance.enableLocalSearchIndex,
|
'enableLocalSearchIndex': instance.enableLocalSearchIndex,
|
||||||
'indexPrivateTabs': instance.indexPrivateTabs,
|
'indexPrivateTabs': instance.indexPrivateTabs,
|
||||||
'acceptSuggestionOnSubmit': instance.acceptSuggestionOnSubmit,
|
'acceptSuggestionOnSubmit': instance.acceptSuggestionOnSubmit,
|
||||||
|
|||||||
@@ -268,6 +268,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
|||||||
'externalAppIntentPolicies': settings['externalAppIntentPolicies']
|
'externalAppIntentPolicies': settings['externalAppIntentPolicies']
|
||||||
?.readAs(DriftSqlType.string, db.typeMapping)
|
?.readAs(DriftSqlType.string, db.typeMapping)
|
||||||
.mapNotNull(jsonDecode),
|
.mapNotNull(jsonDecode),
|
||||||
|
'customTabsEnabled': settings['customTabsEnabled']?.readAs(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
db.typeMapping,
|
||||||
|
),
|
||||||
'enableLocalSearchIndex': settings['enableLocalSearchIndex']?.readAs(
|
'enableLocalSearchIndex': settings['enableLocalSearchIndex']?.readAs(
|
||||||
DriftSqlType.bool,
|
DriftSqlType.bool,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'9ee41d8283340300ec295d318ade92c15b19426d';
|
r'4e72c8ebed8b08ced417ca24d6e4a840f2abf1be';
|
||||||
|
|
||||||
abstract class _$GeneralSettingsRepository
|
abstract class _$GeneralSettingsRepository
|
||||||
extends $StreamNotifier<GeneralSettings> {
|
extends $StreamNotifier<GeneralSettings> {
|
||||||
|
|||||||
+28
-15
@@ -153,12 +153,14 @@ class IntentReceiverActivity : Activity() {
|
|||||||
// Flutter-side to handle (search, PDF display, etc.).
|
// Flutter-side to handle (search, PDF display, etc.).
|
||||||
if (intent.action == Intent.ACTION_SEND) {
|
if (intent.action == Intent.ACTION_SEND) {
|
||||||
val shareUrl = extractShareUrl(intent)
|
val shareUrl = extractShareUrl(intent)
|
||||||
if (shareUrl != null) {
|
if (shareUrl != null &&
|
||||||
|
IntentGatekeeperPreferences.isCustomTabsEnabled(applicationContext)
|
||||||
|
) {
|
||||||
Log.d(TAG, "SHARE intent with URL, routing to custom tab: $shareUrl")
|
Log.d(TAG, "SHARE intent with URL, routing to custom tab: $shareUrl")
|
||||||
handleShareUrlAsCustomTab(intent, shareUrl, privateBrowsingMode)
|
handleShareUrlAsCustomTab(intent, shareUrl, privateBrowsingMode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Log.d(TAG, "SHARE intent without URL, routing to MainActivity")
|
Log.d(TAG, "SHARE intent without URL (or custom tabs disabled), routing to MainActivity")
|
||||||
handleRegularIntent(intent)
|
handleRegularIntent(intent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -193,19 +195,30 @@ class IntentReceiverActivity : Activity() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val processors = listOf(
|
// When the user disables the Custom Tabs feature, external Custom Tab
|
||||||
"CustomTab" to CustomTabIntentProcessor(
|
// intents are not handled here; they fall through to the main browser
|
||||||
components.useCases.customTabsUseCases.add,
|
// via handleRegularIntent(). PWA processing is unaffected.
|
||||||
resources,
|
val customTabsEnabled = IntentGatekeeperPreferences.isCustomTabsEnabled(applicationContext)
|
||||||
isPrivate = privateBrowsingMode,
|
|
||||||
),
|
val processors = buildList {
|
||||||
"PWA" to WebAppIntentProcessor(
|
if (customTabsEnabled) {
|
||||||
components.core.store,
|
add(
|
||||||
components.useCases.customTabsUseCases.addWebApp,
|
"CustomTab" to CustomTabIntentProcessor(
|
||||||
components.useCases.sessionUseCases.loadUrl,
|
components.useCases.customTabsUseCases.add,
|
||||||
components.core.webAppManifestStorage,
|
resources,
|
||||||
),
|
isPrivate = privateBrowsingMode,
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
add(
|
||||||
|
"PWA" to WebAppIntentProcessor(
|
||||||
|
components.core.store,
|
||||||
|
components.useCases.customTabsUseCases.addWebApp,
|
||||||
|
components.useCases.sessionUseCases.loadUrl,
|
||||||
|
components.core.webAppManifestStorage,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
for ((name, processor) in processors) {
|
for ((name, processor) in processors) {
|
||||||
Log.d(TAG, "Trying $name processor...")
|
Log.d(TAG, "Trying $name processor...")
|
||||||
|
|||||||
+10
@@ -21,6 +21,7 @@ import java.util.UUID
|
|||||||
object IntentGatekeeperPreferences {
|
object IntentGatekeeperPreferences {
|
||||||
const val PREFS_NAME = "weblibre_intent_gatekeeper"
|
const val PREFS_NAME = "weblibre_intent_gatekeeper"
|
||||||
const val KEY_ENABLED = "enabled"
|
const val KEY_ENABLED = "enabled"
|
||||||
|
const val KEY_CUSTOM_TABS_ENABLED = "custom_tabs_enabled"
|
||||||
const val KEY_BLOCKED_PACKAGES = "blocked_packages"
|
const val KEY_BLOCKED_PACKAGES = "blocked_packages"
|
||||||
const val KEY_PENDING_ALWAYS_ALLOW = "pending_always_allow"
|
const val KEY_PENDING_ALWAYS_ALLOW = "pending_always_allow"
|
||||||
private const val KEY_NOTIFICATION_APPROVAL_TOKENS = "notification_approval_tokens"
|
private const val KEY_NOTIFICATION_APPROVAL_TOKENS = "notification_approval_tokens"
|
||||||
@@ -32,6 +33,15 @@ object IntentGatekeeperPreferences {
|
|||||||
fun isEnabled(context: Context): Boolean =
|
fun isEnabled(context: Context): Boolean =
|
||||||
get(context).getBoolean(KEY_ENABLED, false)
|
get(context).getBoolean(KEY_ENABLED, false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether external Custom Tab (and share-with-URL) intents should be
|
||||||
|
* handled as lightweight custom-tab activities. When false,
|
||||||
|
* [IntentReceiverActivity] routes them to the main browser instead.
|
||||||
|
* Defaults to true so the feature is active until the user opts out.
|
||||||
|
*/
|
||||||
|
fun isCustomTabsEnabled(context: Context): Boolean =
|
||||||
|
get(context).getBoolean(KEY_CUSTOM_TABS_ENABLED, true)
|
||||||
|
|
||||||
fun isBlocked(context: Context, packageName: String): Boolean {
|
fun isBlocked(context: Context, packageName: String): Boolean {
|
||||||
val prefs = get(context)
|
val prefs = get(context)
|
||||||
if (!prefs.getBoolean(KEY_ENABLED, false)) return false
|
if (!prefs.getBoolean(KEY_ENABLED, false)) return false
|
||||||
|
|||||||
+8
@@ -23,6 +23,7 @@ class IntentGatekeeperHostApiImpl(private val context: Context) : IntentGatekeep
|
|||||||
companion object {
|
companion object {
|
||||||
private const val PREFS_NAME = "weblibre_intent_gatekeeper"
|
private const val PREFS_NAME = "weblibre_intent_gatekeeper"
|
||||||
private const val KEY_ENABLED = "enabled"
|
private const val KEY_ENABLED = "enabled"
|
||||||
|
private const val KEY_CUSTOM_TABS_ENABLED = "custom_tabs_enabled"
|
||||||
private const val KEY_BLOCKED_PACKAGES = "blocked_packages"
|
private const val KEY_BLOCKED_PACKAGES = "blocked_packages"
|
||||||
private const val KEY_PENDING_ALWAYS_ALLOW = "pending_always_allow"
|
private const val KEY_PENDING_ALWAYS_ALLOW = "pending_always_allow"
|
||||||
}
|
}
|
||||||
@@ -35,6 +36,13 @@ class IntentGatekeeperHostApiImpl(private val context: Context) : IntentGatekeep
|
|||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setCustomTabsEnabled(enabled: Boolean) {
|
||||||
|
val prefs = context.applicationContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
prefs.edit()
|
||||||
|
.putBoolean(KEY_CUSTOM_TABS_ENABLED, enabled)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
override fun resolvePackageLabel(packageName: String): String? {
|
override fun resolvePackageLabel(packageName: String): String? {
|
||||||
return try {
|
return try {
|
||||||
val pm = context.applicationContext.packageManager
|
val pm = context.applicationContext.packageManager
|
||||||
|
|||||||
+25
@@ -340,6 +340,13 @@ interface IntentGatekeeperHostApi {
|
|||||||
* [IntentReceiverActivity] can reject intents without launching Flutter.
|
* [IntentReceiverActivity] can reject intents without launching Flutter.
|
||||||
*/
|
*/
|
||||||
fun setConfig(enabled: Boolean, blockedPackages: List<String>)
|
fun setConfig(enabled: Boolean, blockedPackages: List<String>)
|
||||||
|
/**
|
||||||
|
* Replicates whether the Custom Tabs feature is enabled to the native side.
|
||||||
|
* When disabled, [IntentReceiverActivity] routes external Custom Tab and
|
||||||
|
* share-with-URL intents to the main browser instead of launching the
|
||||||
|
* stripped-down custom-tab activity. Defaults to enabled on the native side.
|
||||||
|
*/
|
||||||
|
fun setCustomTabsEnabled(enabled: Boolean)
|
||||||
/**
|
/**
|
||||||
* Resolves a package name to its user-visible application label via
|
* Resolves a package name to its user-visible application label via
|
||||||
* [PackageManager]. Returns `null` if the package is not installed or the
|
* [PackageManager]. Returns `null` if the package is not installed or the
|
||||||
@@ -388,6 +395,24 @@ interface IntentGatekeeperHostApi {
|
|||||||
channel.setMessageHandler(null)
|
channel.setMessageHandler(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
run {
|
||||||
|
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.setCustomTabsEnabled$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.setCustomTabsEnabled(enabledArg)
|
||||||
|
listOf(null)
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
IntentPigeonUtils.wrapError(exception)
|
||||||
|
}
|
||||||
|
reply.reply(wrapped)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channel.setMessageHandler(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
run {
|
run {
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.resolvePackageLabel$separatedMessageChannelSuffix", codec)
|
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.resolvePackageLabel$separatedMessageChannelSuffix", codec)
|
||||||
if (api != null) {
|
if (api != null) {
|
||||||
|
|||||||
@@ -301,6 +301,28 @@ class IntentGatekeeperHostApi {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replicates whether the Custom Tabs feature is enabled to the native side.
|
||||||
|
/// When disabled, [IntentReceiverActivity] routes external Custom Tab and
|
||||||
|
/// share-with-URL intents to the main browser instead of launching the
|
||||||
|
/// stripped-down custom-tab activity. Defaults to enabled on the native side.
|
||||||
|
Future<void> setCustomTabsEnabled(bool enabled) async {
|
||||||
|
final pigeonVar_channelName = 'dev.flutter.pigeon.simple_intent_receiver.IntentGatekeeperHostApi.setCustomTabsEnabled$pigeonVar_messageChannelSuffix';
|
||||||
|
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||||
|
pigeonVar_channelName,
|
||||||
|
pigeonChannelCodec,
|
||||||
|
binaryMessenger: pigeonVar_binaryMessenger,
|
||||||
|
);
|
||||||
|
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[enabled]);
|
||||||
|
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||||
|
|
||||||
|
_extractReplyValueOrThrow(
|
||||||
|
pigeonVar_replyList,
|
||||||
|
pigeonVar_channelName,
|
||||||
|
isNullValid: true,
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolves a package name to its user-visible application label via
|
/// Resolves a package name to its user-visible application label via
|
||||||
/// [PackageManager]. Returns `null` if the package is not installed or the
|
/// [PackageManager]. Returns `null` if the package is not installed or the
|
||||||
/// label cannot be resolved.
|
/// label cannot be resolved.
|
||||||
|
|||||||
@@ -69,6 +69,12 @@ abstract class IntentGatekeeperHostApi {
|
|||||||
/// [IntentReceiverActivity] can reject intents without launching Flutter.
|
/// [IntentReceiverActivity] can reject intents without launching Flutter.
|
||||||
void setConfig(bool enabled, List<String> blockedPackages);
|
void setConfig(bool enabled, List<String> blockedPackages);
|
||||||
|
|
||||||
|
/// Replicates whether the Custom Tabs feature is enabled to the native side.
|
||||||
|
/// When disabled, [IntentReceiverActivity] routes external Custom Tab and
|
||||||
|
/// share-with-URL intents to the main browser instead of launching the
|
||||||
|
/// stripped-down custom-tab activity. Defaults to enabled on the native side.
|
||||||
|
void setCustomTabsEnabled(bool enabled);
|
||||||
|
|
||||||
/// Resolves a package name to its user-visible application label via
|
/// Resolves a package name to its user-visible application label via
|
||||||
/// [PackageManager]. Returns `null` if the package is not installed or the
|
/// [PackageManager]. Returns `null` if the package is not installed or the
|
||||||
/// label cannot be resolved.
|
/// label cannot be resolved.
|
||||||
|
|||||||
Reference in New Issue
Block a user