@tduncan / Cortana / commits / ec3d3ff

fix(android): remove SMS MCP from Play build

Google Play restricts READ_SMS to approved core default-handler use. The optional MCP could request and use inbox access without LocalMind holding the default Assistant role, creating privacy and store-review risk. Remove the permission, tool, settings, dependency, localization, and tests so production builds no longer request SMS access.

abdulmominsakib committed Sep 21, 2026 at 11:33 UTC ec3d3ff6d969ef53d20f9607a6adfde71f46a7f8
27 files changed +2 -550
android/app/src/main/AndroidManifest.xml
-1
@@ -13,7 +13,6 @@
13 <uses-permission android:name="android.permission.WRITE_CALENDAR" />
14 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
15 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
16 - <uses-permission android:name="android.permission.READ_SMS" />
16
17 <application
18 android:label="LocalMind"
lib/core/providers/app_providers.dart
-2
@@ -141,8 +141,6 @@ class SettingsNotifier extends Notifier<AppSettings> {
141 _update(state.copyWith(calendarToolsEnabled: value));
142 void setLocationToolsEnabled(bool value) =>
143 _update(state.copyWith(locationToolsEnabled: value));
144 - void setSmsToolsEnabled(bool value) =>
145 - _update(state.copyWith(smsToolsEnabled: value));
144 void setAutoCollapseThinking(bool value) =>
145 _update(state.copyWith(autoCollapseThinking: value));
146
lib/features/chat/data/tools/builtin_tool_provider.dart
-96
@@ -4,17 +4,14 @@ import 'tool_definition.dart';
4 import 'tool_registry.dart';
5 import 'calendar_service.dart';
6 import 'location_service.dart';
7 -import 'sms_service.dart';
7
8 class BuiltInToolProvider implements ToolProvider {
9 final bool calendarToolsEnabled;
10 final bool locationToolsEnabled;
12 - final bool smsToolsEnabled;
11
12 BuiltInToolProvider({
13 this.calendarToolsEnabled = false,
14 this.locationToolsEnabled = false,
17 - this.smsToolsEnabled = false,
15 });
16
17 @override
@@ -142,44 +139,6 @@ class BuiltInToolProvider implements ToolProvider {
139 ]);
140 }
141
145 - if (smsToolsEnabled) {
146 - tools.addAll(const [
147 - ToolDefinition(
148 - name: 'sms.query_messages',
149 - description:
150 - 'Query recent SMS messages from the device inbox and sent box. '
151 - 'Returns sender address, date, kind, and body. '
152 - 'Use this when the user asks to look up a code, '
153 - 'find a message from a sender, or review recent texts. '
154 - 'Android-only; keep counts small and prefer address filters.',
155 - inputSchema: {
156 - 'type': 'object',
157 - 'properties': {
158 - 'address': {
159 - 'type': 'string',
160 - 'description':
161 - 'Optional sender/recipient filter (phone number or name).',
162 - },
163 - 'count': {
164 - 'type': 'integer',
165 - 'description': 'Max messages to return (1-50). Defaults to 20.',
166 - },
167 - 'query': {
168 - 'type': 'string',
169 - 'description':
170 - 'Optional case-insensitive substring filter over address and body.',
171 - },
172 - 'include_body': {
173 - 'type': 'boolean',
174 - 'description': 'Set false for metadata only. Defaults to true.',
175 - },
176 - },
177 - },
178 - providerType: ToolProviderType.builtIn,
179 - ),
180 - ]);
181 - }
182 -
142 return tools;
143 }
144
@@ -208,10 +167,6 @@ class BuiltInToolProvider implements ToolProvider {
167 case 'location.get_current_location':
168 return _getCurrentLocation();
169
211 - // -- SMS tools --
212 - case 'sms.query_messages':
213 - return _querySmsMessages(args);
214 -
170 default:
171 return const ToolExecutionResult.failure('Unknown built-in tool');
172 }
@@ -344,55 +299,4 @@ class BuiltInToolProvider implements ToolProvider {
299 return ToolExecutionResult.failure('Failed to get location: $e');
300 }
301 }
347 -
348 - // ---------------------------------------------------------------------------
349 - // SMS tool implementations
350 - // ---------------------------------------------------------------------------
351 -
352 - Future<ToolExecutionResult> _querySmsMessages(
353 - Map<String, dynamic> args,
354 - ) async {
355 - try {
356 - final sms = SmsService.instance;
357 - if (!await sms.hasAccess()) {
358 - return const ToolExecutionResult.failure(
359 - 'SMS permission not granted. '
360 - 'Please enable SMS Access in Settings.',
361 - );
362 - }
363 -
364 - final address = args['address'] as String?;
365 - final query = args['query'] as String?;
366 - final count = switch (args['count']) {
367 - final int v => v,
368 - final num v => v.toInt(),
369 - _ => 20,
370 - };
371 - final includeBody = switch (args['include_body']) {
372 - final bool v => v,
373 - _ => true,
374 - };
375 -
376 - final result = await sms.queryMessages(
377 - address: address,
378 - count: count,
379 - query: query,
380 - includeBody: includeBody,
381 - );
382 - if (result.isEmpty) {
383 - return ToolExecutionResult.success(
384 - 'No SMS messages found matching the query.',
385 - );
386 - }
387 - return ToolExecutionResult.success(
388 - const JsonEncoder.withIndent(' ').convert(result),
389 - );
390 - } on UnsupportedError catch (e) {
391 - return ToolExecutionResult.failure(e.message ?? e.toString());
392 - } on StateError catch (e) {
393 - return ToolExecutionResult.failure(e.message);
394 - } catch (e) {
395 - return ToolExecutionResult.failure('Failed to query SMS: $e');
396 - }
397 - }
302 }
lib/features/chat/data/tools/sms_service.dart deleted
-117
@@ -1,117 +0,0 @@
1 -import 'dart:io';
2 -
3 -import 'package:flutter_sms_inbox/flutter_sms_inbox.dart';
4 -import 'package:permission_handler/permission_handler.dart';
5 -
6 -/// Thin wrapper around [SmsQuery] + [Permission.sms] for the built-in
7 -/// SMS tools.
8 -///
9 -/// All methods return plain Dart types (strings / maps) so tool results can
10 -/// be serialised without leaking platform model classes into the tool layer.
11 -///
12 -/// SMS is queried on demand only (no background listening, no caching,
13 -/// no persistence). Bodies are returned only on explicit query; callers
14 -/// should keep `count` small and prefer `address` filters.
15 -///
16 -/// Android-only: iOS has no public SMS-read API, so every method throws
17 -/// [UnsupportedError] on iOS.
18 -class SmsService {
19 - SmsService._();
20 - static final instance = SmsService._();
21 -
22 - final SmsQuery _query = SmsQuery();
23 -
24 - // ---------------------------------------------------------------------------
25 - // Permissions
26 - // ---------------------------------------------------------------------------
27 -
28 - /// Request SMS read access. Returns `true` when granted.
29 - ///
30 - /// Returns `false` on iOS (unsupported) without prompting.
31 - Future<bool> requestAccess() async {
32 - if (!Platform.isAndroid) return false;
33 - final status = await Permission.sms.status;
34 - if (status.isGranted) return true;
35 - final result = await Permission.sms.request();
36 - return result.isGranted;
37 - }
38 -
39 - /// Check current permission status without prompting.
40 - Future<bool> hasAccess() async {
41 - if (!Platform.isAndroid) return false;
42 - final status = await Permission.sms.status;
43 - return status.isGranted;
44 - }
45 -
46 - // ---------------------------------------------------------------------------
47 - // SMS — read
48 - // ---------------------------------------------------------------------------
49 -
50 - /// Queries recent SMS messages, newest first when [sort] is true.
51 - ///
52 - /// [count] is clamped to 1..50 (defaults to 20). Pass [address] to
53 - /// restrict to a single sender/recipient, [query] for a case-insensitive
54 - /// substring match against address/body, and [includeBody] to omit bodies
55 - /// (metadata only).
56 - ///
57 - /// Throws [UnsupportedError] on non-Android platforms and [StateError]
58 - /// when SMS permission is missing.
59 - Future<List<Map<String, dynamic>>> queryMessages({
60 - String? address,
61 - int count = 20,
62 - String? query,
63 - bool includeBody = true,
64 - }) async {
65 - if (!Platform.isAndroid) {
66 - throw UnsupportedError(
67 - 'SMS reading is only supported on Android. '
68 - 'iOS does not expose an SMS-read API.',
69 - );
70 - }
71 - if (!await hasAccess()) {
72 - throw StateError(
73 - 'SMS permission not granted. '
74 - 'Please enable SMS Access in Settings.',
75 - );
76 - }
77 -
78 - final safeCount = count.clamp(1, 50);
79 - final trimmedAddress = address?.trim();
80 - final normalizedQuery = query?.trim().toLowerCase();
81 -
82 - final messages = await _query.querySms(
83 - address: (trimmedAddress == null || trimmedAddress.isEmpty)
84 - ? null
85 - : trimmedAddress,
86 - count: safeCount,
87 - kinds: const [SmsQueryKind.inbox, SmsQueryKind.sent],
88 - sort: true,
89 - );
90 -
91 - final filtered = normalizedQuery == null || normalizedQuery.isEmpty
92 - ? messages
93 - : messages
94 - .where((m) {
95 - final haystack = '${m.address ?? ''} ${m.body ?? ''}'
96 - .toLowerCase();
97 - return haystack.contains(normalizedQuery);
98 - })
99 - .toList(growable: false);
100 -
101 - return filtered
102 - .take(safeCount)
103 - .map(
104 - (m) => {
105 - 'id': m.id,
106 - 'address': m.address,
107 - 'date': m.date?.toIso8601String(),
108 - 'date_sent': m.dateSent?.toIso8601String(),
109 - 'kind': m.kind?.name,
110 - 'thread_id': m.threadId,
111 - 'is_read': m.isRead,
112 - if (includeBody) 'body': m.body,
113 - },
114 - )
115 - .toList(growable: false);
116 - }
117 -}
lib/features/chat/providers/tooling_providers.dart
-1
@@ -16,7 +16,6 @@ final builtInToolProviderProvider = Provider<BuiltInToolProvider>((ref) {
16 return BuiltInToolProvider(
17 calendarToolsEnabled: settings.calendarToolsEnabled,
18 locationToolsEnabled: settings.locationToolsEnabled,
19 - smsToolsEnabled: settings.smsToolsEnabled,
19 );
20 });
21
lib/features/mcp/views/mcp_tools_screen.dart
-34
@@ -1,5 +1,3 @@
1 -import 'dart:io';
2 -
1 import 'package:flutter/material.dart';
2 import 'package:flutter_riverpod/flutter_riverpod.dart';
3 import 'package:hugeicons/hugeicons.dart';
@@ -9,7 +7,6 @@ import 'package:shadcn_ui/shadcn_ui.dart';
7 import '../../chat/data/mcp_server_manager.dart';
8 import '../../chat/data/tools/calendar_service.dart';
9 import '../../chat/data/tools/location_service.dart';
12 -import '../../chat/data/tools/sms_service.dart';
10 import '../../chat/data/tools/tool_definition.dart';
11 import '../../chat/providers/chat_mcp_providers.dart';
12 import '../../chat/providers/tooling_providers.dart';
@@ -168,37 +165,6 @@ class McpToolsScreen extends ConsumerWidget {
165 }
166 },
167 ),
171 - if (!Platform.isIOS)
172 - _McpToggleSetting(
173 - label: l10n.sms_access,
174 - description: l10n.sms_access_desc,
175 - value: settings.smsToolsEnabled,
176 - onChanged: (value) async {
177 - if (value) {
178 - final sms = SmsService.instance;
179 - final granted = await sms.requestAccess();
180 - if (granted) {
181 - ref
182 - .read(settingsProvider.notifier)
183 - .setSmsToolsEnabled(true);
184 - } else {
185 - if (context.mounted) {
186 - ScaffoldMessenger.maybeOf(
187 - context,
188 - )?.showSnackBar(
189 - SnackBar(
190 - content: Text(l10n.sms_permission_denied),
191 - ),
192 - );
193 - }
194 - }
195 - } else {
196 - ref
197 - .read(settingsProvider.notifier)
198 - .setSmsToolsEnabled(false);
199 - }
200 - },
201 - ),
168 _McpToggleSetting(
169 label: l10n.enable_example_server,
170 description: l10n.example_mcp_server_desc,
lib/features/settings/data/models/app_settings.dart
-6
@@ -59,7 +59,6 @@ class AppSettings {
59 final bool showSystemMessagesInChat;
60 final bool calendarToolsEnabled;
61 final bool locationToolsEnabled;
62 - final bool smsToolsEnabled;
62 final bool autoCollapseThinking;
63 final List<McpIntegration> savedMcpIntegrations;
64
@@ -110,7 +109,6 @@ class AppSettings {
109 this.showSystemMessagesInChat = true,
110 this.calendarToolsEnabled = false,
111 this.locationToolsEnabled = false,
113 - this.smsToolsEnabled = false,
112 this.autoCollapseThinking = false,
113 this.savedMcpIntegrations = const [],
114 });
@@ -162,7 +160,6 @@ class AppSettings {
160 bool? showSystemMessagesInChat,
161 bool? calendarToolsEnabled,
162 bool? locationToolsEnabled,
165 - bool? smsToolsEnabled,
163 bool? autoCollapseThinking,
164 List<McpIntegration>? savedMcpIntegrations,
165 }) {
@@ -236,7 +233,6 @@ class AppSettings {
233 showSystemMessagesInChat ?? this.showSystemMessagesInChat,
234 calendarToolsEnabled: calendarToolsEnabled ?? this.calendarToolsEnabled,
235 locationToolsEnabled: locationToolsEnabled ?? this.locationToolsEnabled,
239 - smsToolsEnabled: smsToolsEnabled ?? this.smsToolsEnabled,
236 autoCollapseThinking: autoCollapseThinking ?? this.autoCollapseThinking,
237 savedMcpIntegrations: savedMcpIntegrations ?? this.savedMcpIntegrations,
238 );
@@ -290,7 +286,6 @@ class AppSettings {
286 'showSystemMessagesInChat': showSystemMessagesInChat,
287 'calendarToolsEnabled': calendarToolsEnabled,
288 'locationToolsEnabled': locationToolsEnabled,
293 - 'smsToolsEnabled': smsToolsEnabled,
289 'autoCollapseThinking': autoCollapseThinking,
290 'savedMcpIntegrations': savedMcpIntegrations
291 .map((i) => i.toJson())
@@ -348,7 +343,6 @@ class AppSettings {
343 showSystemMessagesInChat: map['showSystemMessagesInChat'] ?? true,
344 calendarToolsEnabled: map['calendarToolsEnabled'] ?? false,
345 locationToolsEnabled: map['locationToolsEnabled'] ?? false,
351 - smsToolsEnabled: map['smsToolsEnabled'] ?? false,
346 autoCollapseThinking: map['autoCollapseThinking'] ?? false,
347 savedMcpIntegrations: _parseSavedMcpIntegrations(
348 map['savedMcpIntegrations'],
lib/l10n/app_en.arb
-12
@@ -3399,18 +3399,6 @@
3399 "@location_permission_denied": {
3400 "description": "Snackbar message when location permission is denied"
3401 },
3402 - "sms_access": "SMS Access",
3403 - "@sms_access": {
3404 - "description": "Toggle for SMS tools feature"
3405 - },
3406 - "sms_access_desc": "Allow AI to read recent SMS messages (e.g. codes, sender lookup)",
3407 - "@sms_access_desc": {
3408 - "description": "Description for SMS tools toggle"
3409 - },
3410 - "sms_permission_denied": "SMS permission denied. Please grant SMS access in your device settings.",
3411 - "@sms_permission_denied": {
3412 - "description": "Snackbar message when SMS permission is denied"
3413 - },
3402 "builtin_ai_not_supported": "Built-in AI is not supported on this device.",
3403 "@builtin_ai_not_supported": {
3404 "description": "Error shown when built-in AI (Gemini Nano / Apple Intelligence) is not supported on the user's hardware or OS"
lib/l10n/app_localizations.dart
-18
@@ -5745,24 +5745,6 @@ abstract class AppLocalizations {
5745 /// **'Location permission denied. Please grant location access in your device settings.'**
5746 String get location_permission_denied;
5747
5748 - /// Toggle for SMS tools feature
5749 - ///
5750 - /// In en, this message translates to:
5751 - /// **'SMS Access'**
5752 - String get sms_access;
5753 -
5754 - /// Description for SMS tools toggle
5755 - ///
5756 - /// In en, this message translates to:
5757 - /// **'Allow AI to read recent SMS messages (e.g. codes, sender lookup)'**
5758 - String get sms_access_desc;
5759 -
5760 - /// Snackbar message when SMS permission is denied
5761 - ///
5762 - /// In en, this message translates to:
5763 - /// **'SMS permission denied. Please grant SMS access in your device settings.'**
5764 - String get sms_permission_denied;
5765 -
5748 /// Error shown when built-in AI (Gemini Nano / Apple Intelligence) is not supported on the user's hardware or OS
5749 ///
5750 /// In en, this message translates to:
lib/l10n/app_localizations_ar.dart
-11
@@ -3077,17 +3077,6 @@ class AppLocalizationsAr extends AppLocalizations {
3077 String get location_permission_denied =>
3078 'Location permission denied. Please grant location access in your device settings.';
3079
3080 - @override
3081 - String get sms_access => 'SMS Access';
3082 -
3083 - @override
3084 - String get sms_access_desc =>
3085 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3086 -
3087 - @override
3088 - String get sms_permission_denied =>
3089 - 'SMS permission denied. Please grant SMS access in your device settings.';
3090 -
3080 @override
3081 String get builtin_ai_not_supported =>
3082 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_bn.dart
-11
@@ -3103,17 +3103,6 @@ class AppLocalizationsBn extends AppLocalizations {
3103 String get location_permission_denied =>
3104 'Location permission denied. Please grant location access in your device settings.';
3105
3106 - @override
3107 - String get sms_access => 'SMS Access';
3108 -
3109 - @override
3110 - String get sms_access_desc =>
3111 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3112 -
3113 - @override
3114 - String get sms_permission_denied =>
3115 - 'SMS permission denied. Please grant SMS access in your device settings.';
3116 -
3106 @override
3107 String get builtin_ai_not_supported =>
3108 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_de.dart
-11
@@ -3092,17 +3092,6 @@ class AppLocalizationsDe extends AppLocalizations {
3092 String get location_permission_denied =>
3093 'Location permission denied. Please grant location access in your device settings.';
3094
3095 - @override
3096 - String get sms_access => 'SMS Access';
3097 -
3098 - @override
3099 - String get sms_access_desc =>
3100 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3101 -
3102 - @override
3103 - String get sms_permission_denied =>
3104 - 'SMS permission denied. Please grant SMS access in your device settings.';
3105 -
3095 @override
3096 String get builtin_ai_not_supported =>
3097 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_en.dart
-11
@@ -3082,17 +3082,6 @@ class AppLocalizationsEn extends AppLocalizations {
3082 String get location_permission_denied =>
3083 'Location permission denied. Please grant location access in your device settings.';
3084
3085 - @override
3086 - String get sms_access => 'SMS Access';
3087 -
3088 - @override
3089 - String get sms_access_desc =>
3090 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3091 -
3092 - @override
3093 - String get sms_permission_denied =>
3094 - 'SMS permission denied. Please grant SMS access in your device settings.';
3095 -
3085 @override
3086 String get builtin_ai_not_supported =>
3087 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_es.dart
-11
@@ -3106,17 +3106,6 @@ class AppLocalizationsEs extends AppLocalizations {
3106 String get location_permission_denied =>
3107 'Location permission denied. Please grant location access in your device settings.';
3108
3109 - @override
3110 - String get sms_access => 'SMS Access';
3111 -
3112 - @override
3113 - String get sms_access_desc =>
3114 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3115 -
3116 - @override
3117 - String get sms_permission_denied =>
3118 - 'SMS permission denied. Please grant SMS access in your device settings.';
3119 -
3109 @override
3110 String get builtin_ai_not_supported =>
3111 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_fr.dart
-11
@@ -3095,17 +3095,6 @@ class AppLocalizationsFr extends AppLocalizations {
3095 String get location_permission_denied =>
3096 'Location permission denied. Please grant location access in your device settings.';
3097
3098 - @override
3099 - String get sms_access => 'SMS Access';
3100 -
3101 - @override
3102 - String get sms_access_desc =>
3103 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3104 -
3105 - @override
3106 - String get sms_permission_denied =>
3107 - 'SMS permission denied. Please grant SMS access in your device settings.';
3108 -
3098 @override
3099 String get builtin_ai_not_supported =>
3100 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_hi.dart
-11
@@ -3093,17 +3093,6 @@ class AppLocalizationsHi extends AppLocalizations {
3093 String get location_permission_denied =>
3094 'Location permission denied. Please grant location access in your device settings.';
3095
3096 - @override
3097 - String get sms_access => 'SMS Access';
3098 -
3099 - @override
3100 - String get sms_access_desc =>
3101 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3102 -
3103 - @override
3104 - String get sms_permission_denied =>
3105 - 'SMS permission denied. Please grant SMS access in your device settings.';
3106 -
3096 @override
3097 String get builtin_ai_not_supported =>
3098 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_it.dart
-11
@@ -3109,17 +3109,6 @@ class AppLocalizationsIt extends AppLocalizations {
3109 String get location_permission_denied =>
3110 'Location permission denied. Please grant location access in your device settings.';
3111
3112 - @override
3113 - String get sms_access => 'SMS Access';
3114 -
3115 - @override
3116 - String get sms_access_desc =>
3117 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3118 -
3119 - @override
3120 - String get sms_permission_denied =>
3121 - 'SMS permission denied. Please grant SMS access in your device settings.';
3122 -
3112 @override
3113 String get builtin_ai_not_supported =>
3114 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_ja.dart
-11
@@ -3032,17 +3032,6 @@ class AppLocalizationsJa extends AppLocalizations {
3032 String get location_permission_denied =>
3033 'Location permission denied. Please grant location access in your device settings.';
3034
3035 - @override
3036 - String get sms_access => 'SMS Access';
3037 -
3038 - @override
3039 - String get sms_access_desc =>
3040 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3041 -
3042 - @override
3043 - String get sms_permission_denied =>
3044 - 'SMS permission denied. Please grant SMS access in your device settings.';
3045 -
3035 @override
3036 String get builtin_ai_not_supported =>
3037 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_ko.dart
-11
@@ -3016,17 +3016,6 @@ class AppLocalizationsKo extends AppLocalizations {
3016 String get location_permission_denied =>
3017 '위치 권한이 거부되었습니다. 기기 설정에서 위치 액세스 권한을 부여하세요.';
3018
3019 - @override
3020 - String get sms_access => 'SMS Access';
3021 -
3022 - @override
3023 - String get sms_access_desc =>
3024 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3025 -
3026 - @override
3027 - String get sms_permission_denied =>
3028 - 'SMS permission denied. Please grant SMS access in your device settings.';
3029 -
3019 @override
3020 String get builtin_ai_not_supported => '내장 AI는 이 장치에서 지원되지 않습니다.';
3021
lib/l10n/app_localizations_pt.dart
-11
@@ -3122,17 +3122,6 @@ class AppLocalizationsPt extends AppLocalizations {
3122 String get location_permission_denied =>
3123 'Permissão de localização negada. Conceda acesso à localização nas configurações do seu dispositivo.';
3124
3125 - @override
3126 - String get sms_access => 'SMS Access';
3127 -
3128 - @override
3129 - String get sms_access_desc =>
3130 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3131 -
3132 - @override
3133 - String get sms_permission_denied =>
3134 - 'SMS permission denied. Please grant SMS access in your device settings.';
3135 -
3125 @override
3126 String get builtin_ai_not_supported =>
3127 'A IA integrada não é compatível com este dispositivo.';
lib/l10n/app_localizations_ru.dart
-11
@@ -3107,17 +3107,6 @@ class AppLocalizationsRu extends AppLocalizations {
3107 String get location_permission_denied =>
3108 'Location permission denied. Please grant location access in your device settings.';
3109
3110 - @override
3111 - String get sms_access => 'SMS Access';
3112 -
3113 - @override
3114 - String get sms_access_desc =>
3115 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3116 -
3117 - @override
3118 - String get sms_permission_denied =>
3119 - 'SMS permission denied. Please grant SMS access in your device settings.';
3120 -
3110 @override
3111 String get builtin_ai_not_supported =>
3112 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_tr.dart
-11
@@ -3112,17 +3112,6 @@ class AppLocalizationsTr extends AppLocalizations {
3112 String get location_permission_denied =>
3113 'Location permission denied. Please grant location access in your device settings.';
3114
3115 - @override
3116 - String get sms_access => 'SMS Access';
3117 -
3118 - @override
3119 - String get sms_access_desc =>
3120 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3121 -
3122 - @override
3123 - String get sms_permission_denied =>
3124 - 'SMS permission denied. Please grant SMS access in your device settings.';
3125 -
3115 @override
3116 String get builtin_ai_not_supported =>
3117 'Built-in AI is not supported on this device.';
lib/l10n/app_localizations_zh.dart
-11
@@ -3008,17 +3008,6 @@ class AppLocalizationsZh extends AppLocalizations {
3008 String get location_permission_denied =>
3009 'Location permission denied. Please grant location access in your device settings.';
3010
3011 - @override
3012 - String get sms_access => 'SMS Access';
3013 -
3014 - @override
3015 - String get sms_access_desc =>
3016 - 'Allow AI to read recent SMS messages (e.g. codes, sender lookup)';
3017 -
3018 - @override
3019 - String get sms_permission_denied =>
3020 - 'SMS permission denied. Please grant SMS access in your device settings.';
3021 -
3011 @override
3012 String get builtin_ai_not_supported =>
3013 'Built-in AI is not supported on this device.';
lib/l10n/untranslated.txt
+2 -44
@@ -17,9 +17,6 @@
17 "location_access",
18 "location_access_desc",
19 "location_permission_denied",
20 - "sms_access",
21 - "sms_access_desc",
22 - "sms_permission_denied",
20 "builtin_ai_not_supported",
21 "builtin_ai_unsupported_desc",
22 "builtin_ai_unsupported_chip",
@@ -48,9 +45,6 @@
45 "location_access",
46 "location_access_desc",
47 "location_permission_denied",
51 - "sms_access",
52 - "sms_access_desc",
53 - "sms_permission_denied",
48 "builtin_ai_not_supported",
49 "builtin_ai_unsupported_desc",
50 "builtin_ai_unsupported_chip",
@@ -79,9 +73,6 @@
73 "location_access",
74 "location_access_desc",
75 "location_permission_denied",
82 - "sms_access",
83 - "sms_access_desc",
84 - "sms_permission_denied",
76 "builtin_ai_not_supported",
77 "builtin_ai_unsupported_desc",
78 "builtin_ai_unsupported_chip",
@@ -110,9 +101,6 @@
101 "location_access",
102 "location_access_desc",
103 "location_permission_denied",
113 - "sms_access",
114 - "sms_access_desc",
115 - "sms_permission_denied",
104 "builtin_ai_not_supported",
105 "builtin_ai_unsupported_desc",
106 "builtin_ai_unsupported_chip",
@@ -141,9 +129,6 @@
129 "location_access",
130 "location_access_desc",
131 "location_permission_denied",
144 - "sms_access",
145 - "sms_access_desc",
146 - "sms_permission_denied",
132 "builtin_ai_not_supported",
133 "builtin_ai_unsupported_desc",
134 "builtin_ai_unsupported_chip",
@@ -172,9 +157,6 @@
157 "location_access",
158 "location_access_desc",
159 "location_permission_denied",
175 - "sms_access",
176 - "sms_access_desc",
177 - "sms_permission_denied",
160 "builtin_ai_not_supported",
161 "builtin_ai_unsupported_desc",
162 "builtin_ai_unsupported_chip",
@@ -203,9 +185,6 @@
185 "location_access",
186 "location_access_desc",
187 "location_permission_denied",
206 - "sms_access",
207 - "sms_access_desc",
208 - "sms_permission_denied",
188 "builtin_ai_not_supported",
189 "builtin_ai_unsupported_desc",
190 "builtin_ai_unsupported_chip",
@@ -234,9 +213,6 @@
213 "location_access",
214 "location_access_desc",
215 "location_permission_denied",
237 - "sms_access",
238 - "sms_access_desc",
239 - "sms_permission_denied",
216 "builtin_ai_not_supported",
217 "builtin_ai_unsupported_desc",
218 "builtin_ai_unsupported_chip",
@@ -254,10 +230,7 @@
230 "gguf_is_projector_file",
231 "gguf_projector_url_label",
232 "gguf_projector_url_hint",
257 - "gguf_vision_not_supported_error",
258 - "sms_access",
259 - "sms_access_desc",
260 - "sms_permission_denied"
233 + "gguf_vision_not_supported_error"
234 ],
235
236 "pt": [
@@ -271,10 +244,7 @@
244 "gguf_is_projector_file",
245 "gguf_projector_url_label",
246 "gguf_projector_url_hint",
274 - "gguf_vision_not_supported_error",
275 - "sms_access",
276 - "sms_access_desc",
277 - "sms_permission_denied"
247 + "gguf_vision_not_supported_error"
248 ],
249
250 "ru": [
@@ -299,9 +269,6 @@
269 "location_access",
270 "location_access_desc",
271 "location_permission_denied",
302 - "sms_access",
303 - "sms_access_desc",
304 - "sms_permission_denied",
272 "builtin_ai_not_supported",
273 "builtin_ai_unsupported_desc",
274 "builtin_ai_unsupported_chip",
@@ -330,9 +297,6 @@
297 "location_access",
298 "location_access_desc",
299 "location_permission_denied",
333 - "sms_access",
334 - "sms_access_desc",
335 - "sms_permission_denied",
300 "builtin_ai_not_supported",
301 "builtin_ai_unsupported_desc",
302 "builtin_ai_unsupported_chip",
@@ -361,9 +325,6 @@
325 "location_access",
326 "location_access_desc",
327 "location_permission_denied",
364 - "sms_access",
365 - "sms_access_desc",
366 - "sms_permission_denied",
328 "builtin_ai_not_supported",
329 "builtin_ai_unsupported_desc",
330 "builtin_ai_unsupported_chip",
@@ -392,9 +353,6 @@
353 "location_access",
354 "location_access_desc",
355 "location_permission_denied",
395 - "sms_access",
396 - "sms_access_desc",
397 - "sms_permission_denied",
356 "builtin_ai_not_supported",
357 "builtin_ai_unsupported_desc",
358 "builtin_ai_unsupported_chip",
pubspec.lock
-8
@@ -770,14 +770,6 @@ packages:
770 url: "https://pub.dev"
771 source: hosted
772 version: "0.1.3"
773 - flutter_sms_inbox:
774 - dependency: "direct main"
775 - description:
776 - name: flutter_sms_inbox
777 - sha256: "319721d50e5502ce811bb4ba2bbc9d12396da7a5764558087dc88d4b5909bcbb"
778 - url: "https://pub.dev"
779 - source: hosted
780 - version: "1.0.5"
773 flutter_svg:
774 dependency: transitive
775 description:
pubspec.yaml
-1
@@ -94,7 +94,6 @@ dependencies:
94 flutter_gemma_builtin_ai: ^0.2.1
95 geolocator: ^14.0.3
96 geocoding: ^5.0.0
97 - flutter_sms_inbox: ^1.0.5
97
98 dev_dependencies:
99 flutter_test:
test/features/chat/tools/builtin_sms_tool_test.dart deleted
-56
@@ -1,56 +0,0 @@
1 -import 'package:flutter_test/flutter_test.dart';
2 -import 'package:localmind/features/chat/data/tools/builtin_tool_provider.dart';
3 -import 'package:localmind/features/settings/data/models/app_settings.dart';
4 -
5 -void main() {
6 - group('SMS built-in tool gating', () {
7 - test('sms tool is off by default', () async {
8 - final provider = BuiltInToolProvider();
9 - final tools = await provider.listTools();
10 - expect(tools.any((t) => t.name == 'sms.query_messages'), isFalse);
11 - });
12 -
13 - test('sms tool is listed when enabled', () async {
14 - final provider = BuiltInToolProvider(smsToolsEnabled: true);
15 - final tools = await provider.listTools();
16 - expect(tools.any((t) => t.name == 'sms.query_messages'), isTrue);
17 - });
18 -
19 - test('calendar/location flags alone do not enable sms', () async {
20 - final provider = BuiltInToolProvider(
21 - calendarToolsEnabled: true,
22 - locationToolsEnabled: true,
23 - );
24 - final tools = await provider.listTools();
25 - expect(tools.any((t) => t.name == 'sms.query_messages'), isFalse);
26 - expect(tools.any((t) => t.name.startsWith('calendar.')), isTrue);
27 - expect(
28 - tools.any((t) => t.name == 'location.get_current_location'),
29 - isTrue,
30 - );
31 - });
32 -
33 - test('executing sms tool without permission fails gracefully', () async {
34 - final provider = BuiltInToolProvider(smsToolsEnabled: true);
35 - final result = await provider.execute('sms.query_messages', {});
36 - expect(result.success, isFalse);
37 - expect(result.error, isNotNull);
38 - });
39 - });
40 -
41 - group('AppSettings smsToolsEnabled', () {
42 - test('defaults to false', () {
43 - expect(AppSettings().smsToolsEnabled, isFalse);
44 - });
45 -
46 - test('survives toMap/fromMap round-trip', () {
47 - final settings = AppSettings().copyWith(smsToolsEnabled: true);
48 - final restored = AppSettings.fromMap(settings.toMap());
49 - expect(restored.smsToolsEnabled, isTrue);
50 - expect(
51 - AppSettings.fromMap(AppSettings().toMap()).smsToolsEnabled,
52 - isFalse,
53 - );
54 - });
55 - });
56 -}