Nitishkumar-ai commited on
Commit
c25dcd7
·
0 Parent(s):

Deploy source code to Hugging Face without binaries

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +53 -0
  2. .metadata +45 -0
  3. README.md +60 -0
  4. analysis_options.yaml +28 -0
  5. analyze_current.txt +39 -0
  6. analyze_final.txt +29 -0
  7. analyze_out.txt +63 -0
  8. analyze_verify.txt +25 -0
  9. android/.gitignore +14 -0
  10. android/app/build.gradle.kts +53 -0
  11. android/app/src/debug/AndroidManifest.xml +7 -0
  12. android/app/src/main/AndroidManifest.xml +108 -0
  13. android/app/src/main/kotlin/in/inmodel/premithus/DomainBlocker.kt +159 -0
  14. android/app/src/main/kotlin/in/inmodel/premithus/KavachaVpnService.kt +335 -0
  15. android/app/src/main/kotlin/in/inmodel/premithus/KeyboardIMEService.kt +77 -0
  16. android/app/src/main/kotlin/in/inmodel/premithus/LockedAppDao.kt +43 -0
  17. android/app/src/main/kotlin/in/inmodel/premithus/MainActivity.kt +273 -0
  18. android/app/src/main/kotlin/in/inmodel/premithus/OverlayService.kt +515 -0
  19. android/app/src/main/kotlin/in/inmodel/premithus/PremithiusAccessibilityService.kt +135 -0
  20. android/app/src/main/kotlin/in/inmodel/premithus/PremithiusDatabase.kt +99 -0
  21. android/app/src/main/kotlin/in/inmodel/premithus/PremithiusWidget.kt +97 -0
  22. android/app/src/main/kotlin/in/inmodel/premithus/SmsReceiver.kt +26 -0
  23. android/app/src/main/kotlin/in/inmodel/premithus/TelemetryHelper.kt +251 -0
  24. android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  25. android/app/src/main/res/drawable/launch_background.xml +12 -0
  26. android/app/src/main/res/layout/widget_4x2.xml +85 -0
  27. android/app/src/main/res/layout/widget_layout.xml +52 -0
  28. android/app/src/main/res/values-night/styles.xml +18 -0
  29. android/app/src/main/res/values/colors.xml +7 -0
  30. android/app/src/main/res/values/strings.xml +8 -0
  31. android/app/src/main/res/values/styles.xml +18 -0
  32. android/app/src/main/res/xml/accessibility_service_config.xml +11 -0
  33. android/app/src/main/res/xml/method.xml +7 -0
  34. android/app/src/main/res/xml/premithius_widget_info.xml +12 -0
  35. android/app/src/profile/AndroidManifest.xml +7 -0
  36. android/build.gradle.kts +25 -0
  37. android/build/reports/problems/problems-report.html +0 -0
  38. android/gradle.properties +2 -0
  39. android/gradle/wrapper/gradle-wrapper.properties +5 -0
  40. android/settings.gradle.kts +26 -0
  41. assets/blocklist/india_scam_domains.txt +68 -0
  42. assets/seed_embeddings.json +0 -0
  43. build_err.txt +296 -0
  44. convert_bert.py +42 -0
  45. demo_script_v0.0.2.md +28 -0
  46. hf_space +1 -0
  47. index.html +19 -0
  48. ios/.gitignore +34 -0
  49. ios/Flutter/AppFrameworkInfo.plist +24 -0
  50. ios/Flutter/Debug.xcconfig +2 -0
.gitignore ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Miscellaneous
2
+ *.class
3
+ *.log
4
+ *.pyc
5
+ *.swp
6
+ .DS_Store
7
+ .atom/
8
+ .build/
9
+ .buildlog/
10
+ .history
11
+ .svn/
12
+ .swiftpm/
13
+ migrate_working_dir/
14
+
15
+ # IntelliJ related
16
+ *.iml
17
+ *.ipr
18
+ *.iws
19
+ .idea/
20
+
21
+ # The .vscode folder contains launch configuration and tasks you configure in
22
+ # VS Code which you may wish to be included in version control, so this line
23
+ # is commented out by default.
24
+ #.vscode/
25
+
26
+ # Flutter/Dart/Pub related
27
+ **/doc/api/
28
+ **/ios/Flutter/.last_build_id
29
+ .dart_tool/
30
+ .flutter-plugins-dependencies
31
+ .pub-cache/
32
+ .pub/
33
+ /build/
34
+ /coverage/
35
+
36
+ # Symbolication related
37
+ app.*.symbols
38
+
39
+ # Obfuscation related
40
+ app.*.map.json
41
+
42
+ # Android Studio will place build artifacts here
43
+ /android/app/debug
44
+ /android/app/profile
45
+ /android/app/release
46
+ rf_env/
47
+ releases/
48
+ *.so
49
+ *.png
50
+ *.tflite
51
+ *.a
52
+ *.zip
53
+ *.jar
.metadata ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file tracks properties of this Flutter project.
2
+ # Used by Flutter tool to assess capabilities and perform upgrades etc.
3
+ #
4
+ # This file should be version controlled and should not be manually edited.
5
+
6
+ version:
7
+ revision: "ff37bef603469fb030f2b72995ab929ccfc227f0"
8
+ channel: "stable"
9
+
10
+ project_type: app
11
+
12
+ # Tracks metadata for the flutter migrate command
13
+ migration:
14
+ platforms:
15
+ - platform: root
16
+ create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
17
+ base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
18
+ - platform: android
19
+ create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
20
+ base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
21
+ - platform: ios
22
+ create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
23
+ base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
24
+ - platform: linux
25
+ create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
26
+ base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
27
+ - platform: macos
28
+ create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
29
+ base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
30
+ - platform: web
31
+ create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
32
+ base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
33
+ - platform: windows
34
+ create_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
35
+ base_revision: ff37bef603469fb030f2b72995ab929ccfc227f0
36
+
37
+ # User provided section
38
+
39
+ # List of Local paths (relative to this file) that should be
40
+ # ignored by the migrate tool.
41
+ #
42
+ # Files that are not part of the templates will be ignored by default.
43
+ unmanaged_files:
44
+ - 'lib/main.dart'
45
+ - 'ios/Runner.xcodeproj/project.pbxproj'
README.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Prem
3
+ emoji: 🔥
4
+ colorFrom: red
5
+ colorTo: yellow
6
+ sdk: static
7
+ pinned: false
8
+ short_description: In device co-pilot
9
+ ---
10
+ # Premithius V0.0.3
11
+ **India-First On-Device AI Security | Zero LLM Footprint | ARMadillo Architecture**
12
+
13
+ Premithius is an uncompromising, edge-native security layer for Android devices. Designed specifically for the Indian cybersecurity context, it proactively intercepts sophisticated threats like ₹1 collect requests, Aadhaar/PAN data leaks, and zero-day scams before they ever reach the user's eyes—all without sending a single byte of personal data to the cloud.
14
+
15
+ ---
16
+
17
+ ## 🛡️ Kavacha Engine (5-Layer Defense)
18
+ Inspired by NVIDIA's ARMadillo architecture, Premithius utilizes a DOCA FLOW-style early-exit pipeline. This ensures maximum efficiency, allowing standard traffic to pass cleanly while trapping anomalies with progressive computational weight.
19
+
20
+ 1. **Layer 0 (Whitelist):** Immediate pass for trusted, verified senders.
21
+ 2. **Layer 1 (India Threat Pack):** Hardened heuristic rules targeting specific local threat vectors (see below).
22
+ 3. **Layer 2 (Vector Similarity):** Sub-millisecond KNN semantic search against offline scam embeddings using `sqlite-vec` (ARM NEON accelerated).
23
+ 4. **Layer 3 (Random Forest):** A lightweight trained ensemble classifier exported to pure Dart via `m2cgen`. Trained on the HuggingFace `india-spam-sms` dataset with 13 custom numerical and categorical features. Scales dynamically during high-risk festival periods.
24
+ 5. **Layer 4 (MobileBERT):** Our final deep-learning fallback layer. Integrates the `mrm8488/bert-tiny-finetuned-sms-spam-detection` model running locally via `tflite_flutter` and a custom-built native Dart WordPiece tokenizer.
25
+
26
+ ---
27
+
28
+ ## 🇮🇳 India Threat Pack
29
+ Premithius is built for the ground reality of Indian digital fraud:
30
+
31
+ * **UPI Firewall:** Natively catches the classic "₹1 collect request" marketplace fraud, scanning for suspicious VPA usage and urgency indicators.
32
+ * **OTP Context Verifier:** Intercepts incoming OTP messages and cross-references them against the active foreground application to prevent OTP-forwarding phishing.
33
+ * **Aadhaar/PAN Data Shield:** A final line of defense baked directly into the custom Premithius Keyboard, warning users *before* they inadvertently send sensitive documents to untrusted contacts.
34
+ * **Festival Calendar:** Scam volume spikes ~340% during major holidays. The pipeline dynamically adjusts its sensitivity multiplier during these critical windows.
35
+
36
+ ---
37
+
38
+ ## 🚀 Edge-Native & Privacy First
39
+ * **Zero LLM Overhead:** V0.0.3 maintains a tiny footprint by running Random Forest directly in Dart arithmetic and utilizing a highly optimized, quantized BERT module instead of a 900MB Qwen2 model.
40
+ * **Data Shield Insights**: A custom Android native Kotlin telemetry layer continuously and securely queries `AppOpsManager` and `UsageStatsManager` in the background. It surfaces hardware access events (Mic/Camera) and compiles local privacy stories translating background behavior for users.
41
+ * **Home Screen Widget**: A completely native Kotlin AppWidget provides users with 4x2 interactive real-time monitoring of their device's security status, avoiding Flutter engine wakelocks entirely.
42
+
43
+ ---
44
+
45
+ ## 🛠️ Build Requirements
46
+
47
+ * Flutter SDK (^3.11.1)
48
+ * Android Studio / Android SDK
49
+ * *Note:* The final release build requires the `sqlite-vec-android:0.1.7` dependency. Ensure your Android `build.gradle` is configured with the correct Maven artifact repositories if retrieving `io.github.asg017` fails during compilation.
50
+
51
+ ```bash
52
+ # Debug Build
53
+ flutter build apk --debug
54
+
55
+ # Release Build
56
+ flutter build apk --release
57
+ ```
58
+
59
+ ---
60
+ *Built for the next billion users. Because security shouldn't require surrendering your privacy.*
analysis_options.yaml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file configures the analyzer, which statically analyzes Dart code to
2
+ # check for errors, warnings, and lints.
3
+ #
4
+ # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5
+ # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6
+ # invoked from the command line by running `flutter analyze`.
7
+
8
+ # The following line activates a set of recommended lints for Flutter apps,
9
+ # packages, and plugins designed to encourage good coding practices.
10
+ include: package:flutter_lints/flutter.yaml
11
+
12
+ linter:
13
+ # The lint rules applied to this project can be customized in the
14
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15
+ # included above or to enable additional rules. A list of all available lints
16
+ # and their documentation is published at https://dart.dev/lints.
17
+ #
18
+ # Instead of disabling a lint rule for the entire project in the
19
+ # section below, it can also be suppressed for a single line of code
20
+ # or a specific dart file by using the `// ignore: name_of_lint` and
21
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
22
+ # producing the lint.
23
+ rules:
24
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
25
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
26
+
27
+ # Additional information about this file can be found at
28
+ # https://dart.dev/guides/language/analysis-options
analyze_current.txt ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Analyzing premithus...
2
+
3
+ info • Don't invoke 'print' in production code • lib/kavacha/kavacha_pipeline.dart:34:5 • avoid_print
4
+ warning • Unused import: 'package:sqflite/sqflite.dart' • lib/kavacha/layers/layer0_whitelist.dart:1:8 • unused_import
5
+ info • Don't invoke 'print' in production code • lib/kavacha/layers/layer4_mobile_bert.dart:15:7 • avoid_print
6
+ info • Parameter 'key' could be a super parameter • lib/keyboard/keyboard_layout.dart:12:9 • use_super_parameters
7
+ info • Invalid use of a private type in a public API • lib/keyboard/keyboard_layout.dart:15:3 • library_private_types_in_public_api
8
+ warning • The value of the field '_hinglish' isn't used • lib/keyboard/keyboard_layout.dart:24:9 • unused_field
9
+ info • Don't use 'BuildContext's across async gaps • lib/keyboard/keyboard_layout.dart:84:35 • use_build_context_synchronously
10
+ info • Parameter 'key' could be a super parameter • lib/keyboard/shortcut_bar.dart:7:9 • use_super_parameters
11
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/keyboard/shortcut_bar.dart:39:24 • deprecated_member_use
12
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/keyboard/shortcut_bar.dart:41:43 • deprecated_member_use
13
+ info • Parameter 'key' could be a super parameter • lib/main.dart:57:9 • use_super_parameters
14
+ info • Parameter 'key' could be a super parameter • lib/onboarding/model_download.dart:6:9 • use_super_parameters
15
+ info • Invalid use of a private type in a public API • lib/onboarding/model_download.dart:9:3 • library_private_types_in_public_api
16
+ info • Parameter 'key' could be a super parameter • lib/onboarding/permission_flow.dart:6:9 • use_super_parameters
17
+ info • Invalid use of a private type in a public API • lib/onboarding/permission_flow.dart:9:3 • library_private_types_in_public_api
18
+ info • Parameter 'key' could be a super parameter • lib/screens/data_shield_screen.dart:4:9 • use_super_parameters
19
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/data_shield_screen.dart:73:33 • deprecated_member_use
20
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/data_shield_screen.dart:83:36 • deprecated_member_use
21
+ info • Don't invoke 'print' in production code • lib/services/grammar_service.dart:14:5 • avoid_print
22
+ info • The private field _isInit could be 'final' • lib/services/llm_service.dart:8:8 • prefer_final_fields
23
+ warning • The value of the field '_isInit' isn't used • lib/services/llm_service.dart:8:8 • unused_field
24
+ warning • Unused import: 'package:flutter/services.dart' • lib/services/scam_service.dart:1:8 • unused_import
25
+ warning • Unused import: 'package:tflite_flutter/tflite_flutter.dart' • lib/services/scam_service.dart:2:8 • unused_import
26
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:38:7 • avoid_print
27
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:40:7 • avoid_print
28
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:62:9 • avoid_print
29
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:86:7 • avoid_print
30
+ info • The imported package 'path' isn't a dependency of the importing package • lib/services/storage_service.dart:2:8 • depend_on_referenced_packages
31
+ info • The imported package 'path' isn't a dependency of the importing package • lib/services/vector_service.dart:4:8 • depend_on_referenced_packages
32
+ warning • Unused import: 'package:path/path.dart' • lib/services/vector_service.dart:4:8 • unused_import
33
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:57:7 • avoid_print
34
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:59:7 • avoid_print
35
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:66:5 • avoid_print
36
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:78:5 • avoid_print
37
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:113:7 • avoid_print
38
+
39
+ 35 issues found. (ran in 4.7s)
analyze_final.txt ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Analyzing premithus...
2
+
3
+ info • Don't invoke 'print' in production code • lib/kavacha/kavacha_pipeline.dart:34:5 • avoid_print
4
+ warning • Unused import: 'package:sqflite/sqflite.dart' • lib/kavacha/layers/layer0_whitelist.dart:1:8 • unused_import
5
+ info • Don't invoke 'print' in production code • lib/kavacha/layers/layer4_mobile_bert.dart:15:7 • avoid_print
6
+ info • Parameter 'key' could be a super parameter • lib/keyboard/keyboard_layout.dart:13:9 • use_super_parameters
7
+ info • Invalid use of a private type in a public API • lib/keyboard/keyboard_layout.dart:16:3 • library_private_types_in_public_api
8
+ warning • The value of the field '_hinglish' isn't used • lib/keyboard/keyboard_layout.dart:25:9 • unused_field
9
+ info • Don't use 'BuildContext's across async gaps • lib/keyboard/keyboard_layout.dart:85:35 • use_build_context_synchronously
10
+ info • Parameter 'key' could be a super parameter • lib/keyboard/shortcut_bar.dart:9:9 • use_super_parameters
11
+ info • Parameter 'key' could be a super parameter • lib/main.dart:57:9 • use_super_parameters
12
+ info • Parameter 'key' could be a super parameter • lib/onboarding/model_download.dart:6:9 • use_super_parameters
13
+ info • Invalid use of a private type in a public API • lib/onboarding/model_download.dart:9:3 • library_private_types_in_public_api
14
+ info • Invalid use of a private type in a public API • lib/onboarding/permission_flow.dart:11:3 • library_private_types_in_public_api
15
+ info • Don't invoke 'print' in production code • lib/services/grammar_service.dart:14:5 • avoid_print
16
+ info • The private field _isInit could be 'final' • lib/services/llm_service.dart:8:8 • prefer_final_fields
17
+ warning • The value of the field '_isInit' isn't used • lib/services/llm_service.dart:8:8 • unused_field
18
+ warning • Duplicate import • lib/services/scam_service.dart:5:8 • duplicate_import
19
+ warning • Duplicate import • lib/services/scam_service.dart:6:8 • duplicate_import
20
+ error • A try block must be followed by an 'on', 'catch', or 'finally' clause • lib/services/scam_service.dart:35:5 • missing_catch_or_finally
21
+ error • Expected to find '}' • lib/services/scam_service.dart:38:3 • expected_token
22
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:82:7 • avoid_print
23
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:56:7 • avoid_print
24
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:58:7 • avoid_print
25
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:65:5 • avoid_print
26
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:77:5 • avoid_print
27
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:112:7 • avoid_print
28
+
29
+ 25 issues found. (ran in 3.5s)
analyze_out.txt ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Analyzing premithus...
2
+
3
+ error • The element type 'Layer3RandomForest' can't be assigned to the list type 'KavachaLayer' • lib/kavacha/kavacha_pipeline.dart:29:7 • list_element_type_not_assignable
4
+ info • Don't invoke 'print' in production code • lib/kavacha/kavacha_pipeline.dart:34:5 • avoid_print
5
+ warning • Unused import: 'package:sqflite/sqflite.dart' • lib/kavacha/layers/layer0_whitelist.dart:1:8 • unused_import
6
+ error • Classes and mixins can only implement other classes and mixins • lib/kavacha/layers/layer3_random_forest.dart:5:37 • implements_non_class
7
+ error • The name 'LayerResult' isn't a type, so it can't be used as a type argument • lib/kavacha/layers/layer3_random_forest.dart:9:10 • non_type_as_type_argument
8
+ warning • The method doesn't override an inherited method • lib/kavacha/layers/layer3_random_forest.dart:9:23 • override_on_non_overriding_member
9
+ error • Undefined class 'SmsContext' • lib/kavacha/layers/layer3_random_forest.dart:9:31 • undefined_class
10
+ error • Undefined name 'LayerResult' • lib/kavacha/layers/layer3_random_forest.dart:14:14 • undefined_identifier
11
+ error • Undefined name 'LayerResult' • lib/kavacha/layers/layer3_random_forest.dart:17:14 • undefined_identifier
12
+ error • Undefined name 'LayerResult' • lib/kavacha/layers/layer3_random_forest.dart:21:12 • undefined_identifier
13
+ error • Undefined class 'SmsContext' • lib/kavacha/layers/layer3_random_forest.dart:24:37 • undefined_class
14
+ info • Don't invoke 'print' in production code • lib/kavacha/layers/layer4_mobile_bert.dart:15:7 • avoid_print
15
+ info • Parameter 'key' could be a super parameter • lib/keyboard/keyboard_layout.dart:12:9 • use_super_parameters
16
+ info • Invalid use of a private type in a public API • lib/keyboard/keyboard_layout.dart:15:3 • library_private_types_in_public_api
17
+ warning • The value of the field '_hinglish' isn't used • lib/keyboard/keyboard_layout.dart:23:9 • unused_field
18
+ error • Undefined name '_grammarService' • lib/keyboard/keyboard_layout.dart:28:5 • undefined_identifier
19
+ error • Undefined name '_grammarService' • lib/keyboard/keyboard_layout.dart:39:23 • undefined_identifier
20
+ info • Don't use 'BuildContext's across async gaps • lib/keyboard/keyboard_layout.dart:83:35 • use_build_context_synchronously
21
+ info • Parameter 'key' could be a super parameter • lib/keyboard/shortcut_bar.dart:7:9 • use_super_parameters
22
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/keyboard/shortcut_bar.dart:39:24 • deprecated_member_use
23
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/keyboard/shortcut_bar.dart:41:43 • deprecated_member_use
24
+ info • Parameter 'key' could be a super parameter • lib/main.dart:57:9 • use_super_parameters
25
+ info • Parameter 'key' could be a super parameter • lib/onboarding/model_download.dart:6:9 • use_super_parameters
26
+ info • Invalid use of a private type in a public API • lib/onboarding/model_download.dart:9:3 • library_private_types_in_public_api
27
+ info • Parameter 'key' could be a super parameter • lib/onboarding/permission_flow.dart:6:9 • use_super_parameters
28
+ info • Invalid use of a private type in a public API • lib/onboarding/permission_flow.dart:9:3 • library_private_types_in_public_api
29
+ info • Parameter 'key' could be a super parameter • lib/screens/data_shield_screen.dart:4:9 • use_super_parameters
30
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/data_shield_screen.dart:73:33 • deprecated_member_use
31
+ info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/data_shield_screen.dart:83:36 • deprecated_member_use
32
+ info • Don't invoke 'print' in production code • lib/services/grammar_service.dart:14:5 • avoid_print
33
+ info • The imported package 'llama_sdk' isn't a dependency of the importing package • lib/services/llm_service.dart:2:8 • depend_on_referenced_packages
34
+ error • Target of URI doesn't exist: 'package:llama_sdk/llama_sdk.dart' • lib/services/llm_service.dart:2:8 • uri_does_not_exist
35
+ info • The private field _isDownloading could be 'final' • lib/services/llm_service.dart:12:8 • prefer_final_fields
36
+ warning • The value of the field '_isDownloading' isn't used • lib/services/llm_service.dart:12:8 • unused_field
37
+ error • Undefined class 'Llama' • lib/services/llm_service.dart:14:3 • undefined_class
38
+ error • The method 'Llama' isn't defined for the type 'LlmService' • lib/services/llm_service.dart:26:16 • undefined_method
39
+ error • The method 'LlamaController' isn't defined for the type 'LlmService' • lib/services/llm_service.dart:26:22 • undefined_method
40
+ info • Don't invoke 'print' in production code • lib/services/llm_service.dart:29:7 • avoid_print
41
+ info • Don't invoke 'print' in production code • lib/services/llm_service.dart:31:7 • avoid_print
42
+ info • Don't invoke 'print' in production code • lib/services/llm_service.dart:45:5 • avoid_print
43
+ error • The method 'UserLlamaMessage' isn't defined for the type 'LlmService' • lib/services/llm_service.dart:67:25 • undefined_method
44
+ info • Don't invoke 'print' in production code • lib/services/llm_service.dart:75:7 • avoid_print
45
+ warning • Unused import: 'package:flutter/services.dart' • lib/services/scam_service.dart:1:8 • unused_import
46
+ warning • Unused import: 'package:tflite_flutter/tflite_flutter.dart' • lib/services/scam_service.dart:2:8 • unused_import
47
+ error • Directives must appear before any declarations • lib/services/scam_service.dart:21:3 • directive_after_declaration
48
+ error • Directives must appear before any declarations • lib/services/scam_service.dart:22:1 • directive_after_declaration
49
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:39:7 • avoid_print
50
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:41:7 • avoid_print
51
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:63:9 • avoid_print
52
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:87:7 • avoid_print
53
+ info • The imported package 'path' isn't a dependency of the importing package • lib/services/storage_service.dart:2:8 • depend_on_referenced_packages
54
+ info • The imported package 'path' isn't a dependency of the importing package • lib/services/vector_service.dart:4:8 • depend_on_referenced_packages
55
+ warning • Unused import: 'package:path/path.dart' • lib/services/vector_service.dart:4:8 • unused_import
56
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:57:7 • avoid_print
57
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:59:7 • avoid_print
58
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:66:5 • avoid_print
59
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:78:5 • avoid_print
60
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:113:7 • avoid_print
61
+ warning • The asset directory 'models/' doesn't exist • pubspec.yaml:74:7 • asset_directory_does_not_exist
62
+ error • The name 'MyApp' isn't a class • test/widget_test.dart:16:35 • creation_with_non_type
63
+
analyze_verify.txt ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Analyzing premithus...
2
+
3
+ info • Don't invoke 'print' in production code • lib/kavacha/kavacha_pipeline.dart:34:5 • avoid_print
4
+ warning • Unused import: 'package:sqflite/sqflite.dart' • lib/kavacha/layers/layer0_whitelist.dart:1:8 • unused_import
5
+ info • Don't invoke 'print' in production code • lib/kavacha/layers/layer4_mobile_bert.dart:15:7 • avoid_print
6
+ info • Parameter 'key' could be a super parameter • lib/keyboard/keyboard_layout.dart:13:9 • use_super_parameters
7
+ info • Invalid use of a private type in a public API • lib/keyboard/keyboard_layout.dart:16:3 • library_private_types_in_public_api
8
+ warning • The value of the field '_hinglish' isn't used • lib/keyboard/keyboard_layout.dart:25:9 • unused_field
9
+ info • Don't use 'BuildContext's across async gaps • lib/keyboard/keyboard_layout.dart:85:35 • use_build_context_synchronously
10
+ info • Parameter 'key' could be a super parameter • lib/keyboard/shortcut_bar.dart:9:9 • use_super_parameters
11
+ info • Parameter 'key' could be a super parameter • lib/main.dart:57:9 • use_super_parameters
12
+ info • Parameter 'key' could be a super parameter • lib/onboarding/model_download.dart:6:9 • use_super_parameters
13
+ info • Invalid use of a private type in a public API • lib/onboarding/model_download.dart:9:3 • library_private_types_in_public_api
14
+ info • Invalid use of a private type in a public API • lib/onboarding/permission_flow.dart:11:3 • library_private_types_in_public_api
15
+ info • Don't invoke 'print' in production code • lib/services/grammar_service.dart:14:5 • avoid_print
16
+ info • The private field _isInit could be 'final' • lib/services/llm_service.dart:8:8 • prefer_final_fields
17
+ warning • The value of the field '_isInit' isn't used • lib/services/llm_service.dart:8:8 • unused_field
18
+ info • Don't invoke 'print' in production code • lib/services/scam_service.dart:83:7 • avoid_print
19
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:56:7 • avoid_print
20
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:58:7 • avoid_print
21
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:65:5 • avoid_print
22
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:77:5 • avoid_print
23
+ info • Don't invoke 'print' in production code • lib/services/vector_service.dart:112:7 • avoid_print
24
+
25
+ 21 issues found. (ran in 3.3s)
android/.gitignore ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradle-wrapper.jar
2
+ /.gradle
3
+ /captures/
4
+ /gradlew
5
+ /gradlew.bat
6
+ /local.properties
7
+ GeneratedPluginRegistrant.java
8
+ .cxx/
9
+
10
+ # Remember to never publicly share your keystore.
11
+ # See https://flutter.dev/to/reference-keystore
12
+ key.properties
13
+ **/*.keystore
14
+ **/*.jks
android/app/build.gradle.kts ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ plugins {
2
+ id("com.android.application")
3
+ id("kotlin-android")
4
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
5
+ id("dev.flutter.flutter-gradle-plugin")
6
+ }
7
+
8
+ android {
9
+ namespace = "in.inmodel.premithus"
10
+ compileSdk = flutter.compileSdkVersion
11
+ ndkVersion = flutter.ndkVersion
12
+
13
+ compileOptions {
14
+ sourceCompatibility = JavaVersion.VERSION_17
15
+ targetCompatibility = JavaVersion.VERSION_17
16
+ }
17
+
18
+ kotlinOptions {
19
+ jvmTarget = JavaVersion.VERSION_17.toString()
20
+ }
21
+
22
+ defaultConfig {
23
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
24
+ applicationId = "in.inmodel.premithus"
25
+ // You can update the following values to match your application needs.
26
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
27
+ minSdk = flutter.minSdkVersion
28
+ targetSdk = flutter.targetSdkVersion
29
+ versionCode = flutter.versionCode
30
+ versionName = flutter.versionName
31
+
32
+ ndk {
33
+ abiFilters += listOf("arm64-v8a")
34
+ }
35
+ }
36
+
37
+ buildTypes {
38
+ release {
39
+ // TODO: Add your own signing config for the release build.
40
+ // Signing with the debug keys for now, so `flutter run --release` works.
41
+ signingConfig = signingConfigs.getByName("debug")
42
+ }
43
+ }
44
+ }
45
+
46
+ flutter {
47
+ source = "../.."
48
+ }
49
+
50
+ dependencies {
51
+ // sqlite-vec bundled directly in jniLibs/arm64-v8a/libsqlitevec.so
52
+ // No Gradle dependency needed
53
+ }
android/app/src/debug/AndroidManifest.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <!-- The INTERNET permission is required for development. Specifically,
3
+ the Flutter tool needs it to communicate with the running application
4
+ to allow setting breakpoints, to provide hot reload, etc.
5
+ -->
6
+ <uses-permission android:name="android.permission.INTERNET"/>
7
+ </manifest>
android/app/src/main/AndroidManifest.xml ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ xmlns:tools="http://schemas.android.com/tools">
3
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
4
+ <uses-permission android:name="android.permission.READ_SMS"/>
5
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
6
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
7
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
8
+ <uses-permission android:name="android.permission.INTERNET"/>
9
+
10
+ <application
11
+ android:label="premithus"
12
+ android:name="${applicationName}"
13
+ android:icon="@mipmap/ic_launcher">
14
+ <activity
15
+ android:name=".MainActivity"
16
+ android:exported="true"
17
+ android:launchMode="singleTop"
18
+ android:taskAffinity=""
19
+ android:theme="@style/LaunchTheme"
20
+ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
21
+ android:hardwareAccelerated="true"
22
+ android:windowSoftInputMode="adjustResize">
23
+ <!-- Specifies an Android theme to apply to this Activity as soon as
24
+ the Android process has started. This theme is visible to the user
25
+ while the Flutter UI initializes. After that, this theme continues
26
+ to determine the Window background behind the Flutter UI. -->
27
+ <meta-data
28
+ android:name="io.flutter.embedding.android.NormalTheme"
29
+ android:resource="@style/NormalTheme"
30
+ />
31
+ <intent-filter>
32
+ <action android:name="android.intent.action.MAIN"/>
33
+ <category android:name="android.intent.category.LAUNCHER"/>
34
+ </intent-filter>
35
+ </activity>
36
+
37
+ <service android:name=".KeyboardIMEService"
38
+ android:permission="android.permission.BIND_INPUT_METHOD"
39
+ android:exported="true">
40
+ <intent-filter>
41
+ <action android:name="android.view.InputMethod"/>
42
+ </intent-filter>
43
+ <meta-data android:name="android.view.im" android:resource="@xml/method"/>
44
+ </service>
45
+
46
+ <receiver
47
+ android:name=".SmsReceiver"
48
+ android:exported="true"
49
+ android:permission="android.permission.BROADCAST_SMS">
50
+ <intent-filter android:priority="999">
51
+ <action android:name="android.provider.Telephony.SMS_RECEIVED" />
52
+ </intent-filter>
53
+ </receiver>
54
+
55
+ <service
56
+ android:name=".OverlayService"
57
+ android:exported="false"
58
+ android:foregroundServiceType="specialUse" />
59
+
60
+ <receiver android:name=".PremithiusWidget" android:exported="true">
61
+ <intent-filter>
62
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
63
+ </intent-filter>
64
+ <meta-data
65
+ android:name="android.appwidget.provider"
66
+ android:resource="@xml/premithius_widget_info" />
67
+ </receiver>
68
+
69
+ <service
70
+ android:name=".PremithiusAccessibilityService"
71
+ android:exported="true"
72
+ android:label="@string/accessibility_label"
73
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
74
+ <intent-filter>
75
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
76
+ </intent-filter>
77
+ <meta-data
78
+ android:name="android.accessibilityservice"
79
+ android:resource="@xml/accessibility_service_config"/>
80
+ </service>
81
+
82
+ <service
83
+ android:name=".KavachaVpnService"
84
+ android:exported="false"
85
+ android:permission="android.permission.BIND_VPN_SERVICE">
86
+ <intent-filter>
87
+ <action android:name="android.net.VpnService"/>
88
+ </intent-filter>
89
+ </service>
90
+
91
+ <!-- Don't delete the meta-data below.
92
+ This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
93
+ <meta-data
94
+ android:name="flutterEmbedding"
95
+ android:value="2" />
96
+ </application>
97
+ <!-- Required to query activities that can process text, see:
98
+ https://developer.android.com/training/package-visibility and
99
+ https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
100
+
101
+ In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
102
+ <queries>
103
+ <intent>
104
+ <action android:name="android.intent.action.PROCESS_TEXT"/>
105
+ <data android:mimeType="text/plain"/>
106
+ </intent>
107
+ </queries>
108
+ </manifest>
android/app/src/main/kotlin/in/inmodel/premithus/DomainBlocker.kt ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+
6
+ class DomainBlocker(private val context: Context) {
7
+
8
+ private val exactBlocklist = HashSet<String>()
9
+ private val regexPatterns = mutableListOf<Pair<Regex, String>>()
10
+ private val trustedDomains = HashSet<String>()
11
+
12
+ // Known legitimate Indian bank and payment domains
13
+ private val trustedBankDomains = setOf(
14
+ "hdfcbank.com", "netbanking.hdfcbank.com",
15
+ "sbi.co.in", "onlinesbi.sbi.co.in",
16
+ "icicibank.com", "imobileapp.icicibank.com",
17
+ "axisbank.com", "axisnet.axisbank.com",
18
+ "paytm.com", "secure.paytm.com",
19
+ "phonepe.com", "api.phonepe.com",
20
+ "npci.org.in", "upi.npci.org.in",
21
+ "bhimupi.org.in",
22
+ "gpay.app", "pay.google.com",
23
+ "amazon.in", "pay.amazon.in",
24
+ "flipkart.com",
25
+ "swiggy.com", "zomato.com",
26
+ "irctc.co.in", "indianrail.gov.in",
27
+ "incometax.gov.in", "tin.tin.nsdl.com",
28
+ "uidai.gov.in",
29
+ )
30
+
31
+ init {
32
+ loadBlocklists()
33
+ trustedDomains.addAll(trustedBankDomains)
34
+ }
35
+
36
+ private fun loadBlocklists() {
37
+ // Load seed blocklist from assets
38
+ try {
39
+ context.assets.open("blocklist/india_scam_domains.txt")
40
+ .bufferedReader()
41
+ .forEachLine { line ->
42
+ val clean = line.trim().lowercase()
43
+ if (clean.isNotEmpty() && !clean.startsWith("#")) {
44
+ exactBlocklist.add(clean)
45
+ }
46
+ }
47
+ Log.d("DomainBlocker", "Loaded ${exactBlocklist.size} blocked domains")
48
+ } catch (e: Exception) {
49
+ Log.e("DomainBlocker", "Failed to load blocklist: \${e.message}")
50
+ }
51
+
52
+ // Load user-confirmed blocked domains from SQLite via direct path since Flutter owns DB
53
+ try {
54
+ val dbPath = context.getDatabasePath("premithius.db").absolutePath
55
+ val dbFile = java.io.File(dbPath)
56
+ if (dbFile.exists()) {
57
+ val db = android.database.sqlite.SQLiteDatabase.openDatabase(dbPath, null, android.database.sqlite.SQLiteDatabase.OPEN_READONLY)
58
+ val cursor = db.rawQuery("SELECT domain FROM scam_domains", null)
59
+ while (cursor.moveToNext()) {
60
+ exactBlocklist.add(cursor.getString(0).lowercase())
61
+ }
62
+ cursor.close()
63
+ db.close()
64
+ }
65
+ } catch (e: Exception) {
66
+ Log.e("DomainBlocker", "Failed to load user domains: \${e.message}")
67
+ }
68
+
69
+ // Regex patterns for structural scam detection
70
+ regexPatterns.addAll(listOf(
71
+ // Suspicious TLDs
72
+ Regex(""".*\.(xyz|top|click|tk|ml|ga|cf|gq|pw|cc|su)$""") to "Suspicious TLD",
73
+
74
+ // Typosquat: known bank name + extra chars
75
+ Regex(""".*hdfc.*bank.*(?!hdfcbank\.com)""") to "HDFC Typosquat",
76
+ Regex(""".*sbi.*(?!sbi\.co\.in|onlinesbi)""") to "SBI Typosquat",
77
+ Regex(""".*icici.*(?!icicibank\.com)""") to "ICICI Typosquat",
78
+ Regex(""".*paytm.*(?!paytm\.com)""") to "Paytm Typosquat",
79
+ Regex(""".*phonepe.*(?!phonepe\.com)""") to "PhonePe Typosquat",
80
+
81
+ // KYC fraud patterns
82
+ Regex(""".*kyc.*(update|verify|expire|block).*""") to "KYC Fraud",
83
+ Regex(""".*verify.*(kyc|account|aadhar|aadhaar).*""") to "KYC Fraud",
84
+
85
+ // UPI fraud patterns
86
+ Regex(""".*upi.*(reward|prize|cashback|bonus).*""") to "UPI Fraud",
87
+ Regex(""".*collect.*(rs|rupee|inr|money).*""") to "UPI Collect Fraud",
88
+
89
+ // Generic phishing patterns
90
+ Regex(""".*secure.*login.*\.(xyz|net|org|in|co)$""") to "Phishing",
91
+ Regex(""".*account.*(blocked|suspended|expired).*""") to "Account Fraud",
92
+ ))
93
+ }
94
+
95
+ fun check(domain: String): BlockResult {
96
+ val d = domain.lowercase().trimEnd('.')
97
+
98
+ // Step 1: Trusted domain — always allow instantly
99
+ if (trustedDomains.any { d == it || d.endsWith(".$it") }) {
100
+ return BlockResult(isBlocked = false, domain = d, category = "")
101
+ }
102
+
103
+ // Step 2: Exact match in blocklist
104
+ if (exactBlocklist.contains(d)) {
105
+ return BlockResult(isBlocked = true, domain = d, category = "Known Scam Domain")
106
+ }
107
+
108
+ // Step 3: Levenshtein distance check against trusted bank domains
109
+ // Catches: hdfcbannk.com (typo), hdfcbank-kyc.net (subdomain fraud)
110
+ for (trusted in trustedBankDomains) {
111
+ val baseTrusted = trusted.substringBefore(".")
112
+ val baseQuery = d.substringBefore(".")
113
+ if (levenshtein(baseQuery, baseTrusted) in 1..2) {
114
+ return BlockResult(isBlocked = true, domain = d,
115
+ category = "Typosquat — similar to $trusted")
116
+ }
117
+ }
118
+
119
+ // Step 4: Regex pattern matching
120
+ for ((pattern, category) in regexPatterns) {
121
+ // Note: need to handle regex exclusion properly. Since patterns above use negative lookahead incorrectly for exact strings, we might want to ensure we don't block valid domains.
122
+ // Actually the negative lookahead matches at current position. Because Android Kotlin PCRE works.
123
+ if (pattern.containsMatchIn(d)) {
124
+ return BlockResult(isBlocked = true, domain = d, category = category)
125
+ }
126
+ }
127
+
128
+ // Step 5: Allow — not in any blocklist
129
+ return BlockResult(isBlocked = false, domain = d, category = "")
130
+ }
131
+
132
+ // Levenshtein distance — pure Kotlin, no library needed
133
+ private fun levenshtein(a: String, b: String): Int {
134
+ val dp = Array(a.length + 1) { IntArray(b.length + 1) }
135
+ for (i in 0..a.length) dp[i][0] = i
136
+ for (j in 0..b.length) dp[0][j] = j
137
+ for (i in 1..a.length) {
138
+ for (j in 1..b.length) {
139
+ dp[i][j] = if (a[i-1] == b[j-1]) dp[i-1][j-1]
140
+ else 1 + minOf(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
141
+ }
142
+ }
143
+ return dp[a.length][b.length]
144
+ }
145
+
146
+ // Reload user-confirmed domains from SQLite
147
+ // Call after user confirms a scam domain
148
+ fun reload() {
149
+ exactBlocklist.clear()
150
+ regexPatterns.clear()
151
+ loadBlocklists()
152
+ }
153
+ }
154
+
155
+ data class BlockResult(
156
+ val isBlocked: Boolean,
157
+ val domain: String,
158
+ val category: String
159
+ )
android/app/src/main/kotlin/in/inmodel/premithus/KavachaVpnService.kt ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.content.Intent
4
+ import android.net.VpnService
5
+ import android.os.ParcelFileDescriptor
6
+ import android.util.Log
7
+ import java.io.FileInputStream
8
+ import java.io.FileOutputStream
9
+ import java.net.DatagramPacket
10
+ import java.net.DatagramSocket
11
+ import java.net.InetAddress
12
+
13
+ class KavachaVpnService : VpnService() {
14
+
15
+ companion object {
16
+ const val ACTION_START = "ACTION_VPN_START"
17
+ const val ACTION_STOP = "ACTION_VPN_STOP"
18
+ const val CHANNEL = "in.inmodel.premithius/vpn"
19
+ var isRunning = false
20
+ }
21
+
22
+ private var vpnInterface: ParcelFileDescriptor? = null
23
+ private var tunnelThread: Thread? = null
24
+ private lateinit var domainBlocker: DomainBlocker
25
+
26
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
27
+ if (intent?.action == ACTION_STOP) {
28
+ stopVpn()
29
+ return START_NOT_STICKY
30
+ }
31
+ if (intent?.action == "ACTION_RELOAD_BLOCKLIST") {
32
+ if (::domainBlocker.isInitialized) {
33
+ domainBlocker.reload()
34
+ }
35
+ return START_STICKY
36
+ }
37
+ if (!isRunning) startVpn()
38
+ return START_STICKY
39
+ }
40
+
41
+ private fun startVpn() {
42
+ // Build the TUN interface
43
+ val builder = Builder()
44
+ .setSession("Premithius Kavacha")
45
+ .addAddress("10.0.0.2", 24)
46
+ .addDnsServer("10.0.0.1") // our local DNS resolver
47
+ .addRoute("0.0.0.0", 0) // route all traffic
48
+ .setMtu(1500)
49
+ .setBlocking(true)
50
+
51
+ // Exclude Premithius itself from VPN
52
+ // so our DNS forwarding to 1.1.1.1 is not intercepted
53
+ try {
54
+ builder.addDisallowedApplication(packageName)
55
+ } catch (e: Exception) {
56
+ Log.e("KavachaVPN", "Failed to exclude app from VPN: \${e.message}")
57
+ }
58
+
59
+ vpnInterface = builder.establish()
60
+ isRunning = true
61
+
62
+ domainBlocker = DomainBlocker(this)
63
+
64
+ // Start tunnel on background thread
65
+ tunnelThread = Thread {
66
+ runTunnel()
67
+ }.also { it.start() }
68
+
69
+ Log.d("KavachaVPN", "VPN tunnel started")
70
+ notifyFlutter("started")
71
+ }
72
+
73
+ private fun stopVpn() {
74
+ isRunning = false
75
+ tunnelThread?.interrupt()
76
+ try { vpnInterface?.close() } catch (e: Exception) {}
77
+ vpnInterface = null
78
+ Log.d("KavachaVPN", "VPN tunnel stopped")
79
+ notifyFlutter("stopped")
80
+ stopSelf()
81
+ }
82
+
83
+ private fun runTunnel() {
84
+ val vpnFd = vpnInterface?.fileDescriptor ?: return
85
+ val inputStream = FileInputStream(vpnFd)
86
+ val outputStream = FileOutputStream(vpnFd)
87
+
88
+ val packet = ByteArray(32767)
89
+
90
+ while (isRunning && !Thread.interrupted()) {
91
+ try {
92
+ // Read incoming IP packet
93
+ val length = inputStream.read(packet)
94
+ if (length <= 0) continue
95
+
96
+ // Parse and handle — focus on DNS (UDP port 53)
97
+ val handled = handlePacket(packet, length, outputStream)
98
+
99
+ // If not DNS — pass through unchanged
100
+ if (!handled) outputStream.write(packet, 0, length)
101
+
102
+ } catch (e: InterruptedException) {
103
+ break
104
+ } catch (e: Exception) {
105
+ Log.e("KavachaVPN", "Tunnel error: \${e.message}")
106
+ }
107
+ }
108
+ }
109
+
110
+ private fun handlePacket(
111
+ packet: ByteArray,
112
+ length: Int,
113
+ output: FileOutputStream
114
+ ): Boolean {
115
+ // Check if this is an IP packet (version 4)
116
+ if (length < 20) return false
117
+ val ipVersion = (packet[0].toInt() shr 4) and 0xF
118
+ if (ipVersion != 4) return false
119
+
120
+ // Check protocol — 17 = UDP
121
+ val protocol = packet[9].toInt() and 0xFF
122
+ if (protocol != 17) return false
123
+
124
+ // Check destination port — 53 = DNS
125
+ val ipHeaderLen = (packet[0].toInt() and 0xF) * 4
126
+ if (length < ipHeaderLen + 8) return false
127
+ val destPort = ((packet[ipHeaderLen + 2].toInt() and 0xFF) shl 8) or
128
+ (packet[ipHeaderLen + 3].toInt() and 0xFF)
129
+ if (destPort != 53) return false
130
+
131
+ // Extract DNS query payload
132
+ val dnsStart = ipHeaderLen + 8
133
+ val dnsLength = length - dnsStart
134
+ if (dnsLength < 12) return false
135
+ val dnsPayload = packet.copyOfRange(dnsStart, dnsStart + dnsLength)
136
+
137
+ // Parse domain name from DNS query
138
+ val domain = parseDnsQuery(dnsPayload) ?: return false
139
+
140
+ Log.d("KavachaVPN", "DNS query: \$domain")
141
+
142
+ // Check domain against blocklist
143
+ val blockResult = domainBlocker.check(domain)
144
+
145
+ if (blockResult.isBlocked) {
146
+ Log.d("KavachaVPN", "BLOCKED: \$domain — \${blockResult.category}")
147
+
148
+ // Return NXDOMAIN response — domain does not exist
149
+ val nxDomainResponse = buildNxDomainResponse(packet, length, dnsPayload)
150
+ output.write(nxDomainResponse)
151
+
152
+ // Log and alert
153
+ logBlockedDomain(domain, blockResult)
154
+ return true
155
+ }
156
+
157
+ // Safe domain — forward to 1.1.1.1 and return real answer
158
+ val realResponse = forwardDns(dnsPayload, "1.1.1.1")
159
+ if (realResponse != null) {
160
+ val responsePacket = buildResponsePacket(packet, realResponse)
161
+ output.write(responsePacket)
162
+ return true
163
+ }
164
+
165
+ return false
166
+ }
167
+
168
+ private fun logBlockedDomain(domain: String, result: BlockResult) {
169
+ // Log to SQLite (directly into scam_domains + vpn_events)
170
+ Thread {
171
+ try {
172
+ // Assuming path provider defaults for database path
173
+ val dbPath = applicationContext.getDatabasePath("premithius.db").absolutePath
174
+ val db = android.database.sqlite.SQLiteDatabase.openDatabase(dbPath, null, android.database.sqlite.SQLiteDatabase.OPEN_READWRITE)
175
+
176
+ db.execSQL("UPDATE scam_domains SET hit_count = hit_count + 1 WHERE domain = ?", arrayOf(domain))
177
+
178
+ val insertEvent = "INSERT INTO vpn_events (event_type, domain, category, created_at) VALUES (?, ?, ?, ?)"
179
+ db.execSQL(insertEvent, arrayOf("blocked", domain, result.category, System.currentTimeMillis()))
180
+
181
+ db.close()
182
+ } catch (e: Exception) {
183
+ Log.e("KavachaVPN", "Failed to log blocked domain to SQLite: \${e.message}")
184
+ }
185
+ }.start()
186
+
187
+ // Fire overlay alert via OverlayService
188
+ val intent = Intent(this, OverlayService::class.java)
189
+ intent.action = OverlayService.ACTION_SHOW_DOMAIN_BLOCK
190
+ intent.putExtra("domain", domain)
191
+ intent.putExtra("category", result.category)
192
+ startService(intent)
193
+
194
+ // Notify Flutter for VPN stats screen
195
+ notifyFlutter("blocked:\$domain:\${result.category}")
196
+ }
197
+
198
+ private fun notifyFlutter(event: String) {
199
+ // Store in shared prefs — Flutter polls on resume
200
+ // Direct MethodChannel not reliable from background service
201
+ getSharedPreferences("vpn_events", MODE_PRIVATE)
202
+ .edit()
203
+ .putString("last_event", event)
204
+ .putLong("last_event_time", System.currentTimeMillis())
205
+ .apply()
206
+ }
207
+
208
+ override fun onDestroy() {
209
+ stopVpn()
210
+ super.onDestroy()
211
+ }
212
+
213
+ // DNS parsing helpers
214
+
215
+ private fun parseDnsQuery(payload: ByteArray): String? {
216
+ try {
217
+ if (payload.size < 12) return null
218
+ var pos = 12 // Skip DNS header
219
+ val sb = StringBuilder()
220
+ while (pos < payload.size) {
221
+ val len = payload[pos].toInt() and 0xFF
222
+ if (len == 0) break // Root label
223
+ if (len >= 192) return null // Pointer, not supporting compressed query parsing
224
+ pos++
225
+ if (pos + len > payload.size) return null
226
+ for (i in 0 until len) {
227
+ sb.append(payload[pos + i].toInt().toChar())
228
+ }
229
+ sb.append('.')
230
+ pos += len
231
+ }
232
+ return if (sb.isNotEmpty()) sb.toString().trimEnd('.') else null
233
+ } catch (e: Exception) {
234
+ return null
235
+ }
236
+ }
237
+
238
+ private fun buildNxDomainResponse(original: ByteArray, len: Int, dns: ByteArray): ByteArray {
239
+ val response = ByteArray(len)
240
+ System.arraycopy(original, 0, response, 0, len)
241
+
242
+ val ipHeaderLen = (response[0].toInt() and 0xF) * 4
243
+ val udpStart = ipHeaderLen
244
+
245
+ // IP header: Swap Source and Dest IP
246
+ for (i in 0..3) {
247
+ val tmp = response[12 + i]
248
+ response[12 + i] = response[16 + i]
249
+ response[16 + i] = tmp
250
+ }
251
+
252
+ // UDP header: Swap Source and Dest Port
253
+ for (i in 0..1) {
254
+ val tmp = response[udpStart + i]
255
+ response[udpStart + i] = response[udpStart + 2 + i]
256
+ response[udpStart + 2 + i] = tmp
257
+ }
258
+
259
+ // DNS header: QR=1(response), RCODE=3(NXDOMAIN)
260
+ val dnsStart = udpStart + 8
261
+ response[dnsStart + 2] = (response[dnsStart + 2].toInt() or 0x80).toByte() // QR=1
262
+ response[dnsStart + 3] = ((response[dnsStart + 3].toInt() and 0xF0) or 0x03).toByte()
263
+
264
+ // Set ANCOUNT=0, NSCOUNT=0, ARCOUNT=0
265
+ response[dnsStart + 6] = 0; response[dnsStart + 7] = 0
266
+ response[dnsStart + 8] = 0; response[dnsStart + 9] = 0
267
+ response[dnsStart + 10] = 0; response[dnsStart + 11] = 0
268
+
269
+ // Clear UDP checksum
270
+ response[udpStart + 6] = 0
271
+ response[udpStart + 7] = 0
272
+
273
+ return response
274
+ }
275
+
276
+ private fun buildResponsePacket(original: ByteArray, dnsResponse: ByteArray): ByteArray {
277
+ val ipHeaderLen = (original[0].toInt() and 0xF) * 4
278
+ val udpHeaderLen = 8
279
+ val newLen = ipHeaderLen + udpHeaderLen + dnsResponse.size
280
+ val packet = ByteArray(newLen)
281
+
282
+ System.arraycopy(original, 0, packet, 0, ipHeaderLen + udpHeaderLen)
283
+ System.arraycopy(dnsResponse, 0, packet, ipHeaderLen + udpHeaderLen, dnsResponse.size)
284
+
285
+ // IP header Total length
286
+ packet[2] = (newLen shr 8).toByte()
287
+ packet[3] = (newLen and 0xFF).toByte()
288
+
289
+ // Swap IPs
290
+ for (i in 0..3) {
291
+ val tmp = packet[12 + i]
292
+ packet[12 + i] = packet[16 + i]
293
+ packet[16 + i] = tmp
294
+ }
295
+
296
+ // Swap UDP Ports
297
+ val udpStart = ipHeaderLen
298
+ for (i in 0..1) {
299
+ val tmp = packet[udpStart + i]
300
+ packet[udpStart + i] = packet[udpStart + 2 + i]
301
+ packet[udpStart + 2 + i] = tmp
302
+ }
303
+
304
+ // UDP Length
305
+ val udpLen = udpHeaderLen + dnsResponse.size
306
+ packet[udpStart + 4] = (udpLen shr 8).toByte()
307
+ packet[udpStart + 5] = (udpLen and 0xFF).toByte()
308
+
309
+ // Clear UDP checksum
310
+ packet[udpStart + 6] = 0
311
+ packet[udpStart + 7] = 0
312
+
313
+ return packet
314
+ }
315
+
316
+ private fun forwardDns(query: ByteArray, server: String): ByteArray? {
317
+ try {
318
+ val socket = DatagramSocket()
319
+ socket.soTimeout = 3000
320
+ val address = InetAddress.getByName(server)
321
+ val packet = DatagramPacket(query, query.size, address, 53)
322
+ socket.send(packet)
323
+
324
+ val buf = ByteArray(4096)
325
+ val responsePacket = DatagramPacket(buf, buf.size)
326
+ socket.receive(responsePacket)
327
+ socket.close()
328
+
329
+ return buf.copyOfRange(0, responsePacket.length)
330
+ } catch (e: Exception) {
331
+ Log.e("KavachaVPN", "Forward DNS failed: \${e.message}")
332
+ return null
333
+ }
334
+ }
335
+ }
android/app/src/main/kotlin/in/inmodel/premithus/KeyboardIMEService.kt ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.inputmethodservice.InputMethodService
4
+ import android.view.View
5
+ import android.widget.FrameLayout
6
+ import io.flutter.FlutterInjector
7
+ import io.flutter.embedding.android.FlutterView
8
+ import io.flutter.embedding.engine.FlutterEngine
9
+ import io.flutter.embedding.engine.dart.DartExecutor
10
+ import io.flutter.plugin.common.MethodChannel
11
+
12
+ class KeyboardIMEService : InputMethodService() {
13
+
14
+ private lateinit var flutterEngine: FlutterEngine
15
+ private lateinit var flutterView: FlutterView
16
+ private lateinit var methodChannel: MethodChannel
17
+ private val CHANNEL = "in.inmodel.premithus/keyboard"
18
+
19
+ override fun onCreate() {
20
+ super.onCreate()
21
+
22
+ flutterEngine = FlutterEngine(this)
23
+ flutterEngine.dartExecutor.executeDartEntrypoint(
24
+ DartExecutor.DartEntrypoint(
25
+ FlutterInjector.instance().flutterLoader().findAppBundlePath(),
26
+ "keyboardMain"
27
+ )
28
+ )
29
+
30
+ methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
31
+ methodChannel.setMethodCallHandler { call, result ->
32
+ when (call.method) {
33
+ "commitText" -> {
34
+ val text = call.argument<String>("text") ?: ""
35
+ currentInputConnection?.commitText(text, 1)
36
+ result.success(null)
37
+ }
38
+ "deleteBackward" -> {
39
+ currentInputConnection?.deleteSurroundingText(1, 0)
40
+ result.success(null)
41
+ }
42
+ "replaceText" -> {
43
+ val newText = call.argument<String>("text") ?: ""
44
+ currentInputConnection?.deleteSurroundingText(10000, 10000)
45
+ currentInputConnection?.commitText(newText, 1)
46
+ result.success(null)
47
+ }
48
+ "getText" -> {
49
+ val before = currentInputConnection?.getTextBeforeCursor(5000, 0) ?: ""
50
+ val after = currentInputConnection?.getTextAfterCursor(5000, 0) ?: ""
51
+ result.success(before.toString() + after.toString())
52
+ }
53
+ "hideKeyboard" -> {
54
+ requestHideSelf(0)
55
+ result.success(null)
56
+ }
57
+ else -> result.notImplemented()
58
+ }
59
+ }
60
+ }
61
+
62
+ override fun onCreateInputView(): View {
63
+ flutterView = FlutterView(this)
64
+ flutterView.attachToFlutterEngine(flutterEngine)
65
+
66
+ // Wrap in FrameLayout to ensure layout bounds
67
+ val frameLayout = FrameLayout(this)
68
+ frameLayout.addView(flutterView)
69
+ return frameLayout
70
+ }
71
+
72
+ override fun onDestroy() {
73
+ flutterView.detachFromFlutterEngine()
74
+ flutterEngine.destroy()
75
+ super.onDestroy()
76
+ }
77
+ }
android/app/src/main/kotlin/in/inmodel/premithus/LockedAppDao.kt ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.content.ContentValues
4
+ import android.database.sqlite.SQLiteDatabase
5
+
6
+ class LockedAppDao(private val db: SQLiteDatabase) {
7
+
8
+ fun isLocked(packageName: String): Boolean {
9
+ // Check if app is in locked_apps table AND no active temporary unlock
10
+ val cursor = db.rawQuery(
11
+ "SELECT temporary_unlock_until FROM locked_apps WHERE package_name = ?",
12
+ arrayOf(packageName)
13
+ )
14
+ if (!cursor.moveToFirst()) {
15
+ cursor.close()
16
+ return false
17
+ }
18
+ val tempUntil = cursor.getLong(0)
19
+ cursor.close()
20
+
21
+ // If temporary_unlock_until is 0 or in the past, app is locked
22
+ return tempUntil == 0L || System.currentTimeMillis() > tempUntil
23
+ }
24
+
25
+ fun logAccessAttempt(packageName: String, timestamp: Long) {
26
+ // Increment access_attempts in locked_apps
27
+ db.execSQL(
28
+ "UPDATE locked_apps SET access_attempts = access_attempts + 1 WHERE package_name = ?",
29
+ arrayOf(packageName)
30
+ )
31
+ // Insert into access_log
32
+ val values = ContentValues().apply {
33
+ put("package_name", packageName)
34
+ put("was_allowed", 0)
35
+ put("attempted_at", timestamp)
36
+ }
37
+ try {
38
+ db.insert("access_log", null, values)
39
+ } catch (e: Exception) {
40
+ // Table may not exist yet — ignore
41
+ }
42
+ }
43
+ }
android/app/src/main/kotlin/in/inmodel/premithus/MainActivity.kt ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.accessibilityservice.AccessibilityServiceInfo
4
+ import android.content.Context
5
+ import android.content.pm.ApplicationInfo
6
+ import android.content.pm.PackageManager
7
+ import android.os.Bundle
8
+ import android.view.accessibility.AccessibilityManager
9
+ import io.flutter.embedding.android.FlutterActivity
10
+ import io.flutter.embedding.engine.FlutterEngine
11
+ import io.flutter.plugin.common.MethodChannel
12
+ import android.content.Intent
13
+ import android.net.VpnService
14
+ import android.os.Handler
15
+ import android.os.Looper
16
+ import org.json.JSONArray
17
+ import org.json.JSONObject
18
+ import kotlin.concurrent.thread
19
+
20
+ class MainActivity : FlutterActivity() {
21
+
22
+ companion object {
23
+ // Accessibility channel — shared with PremithiusAccessibilityService
24
+ var accessibilityChannel: MethodChannel? = null
25
+
26
+ // Auth channel — shared with OverlayService
27
+ var authChannel: MethodChannel? = null
28
+
29
+ const val VPN_REQUEST_CODE = 1001
30
+ var pendingVpnResult: MethodChannel.Result? = null
31
+ }
32
+
33
+ private val alreadyAlerted = mutableSetOf<String>()
34
+ private val sensorMonitorHandler = Handler(Looper.getMainLooper())
35
+ private val sensorMonitorRunnable = object : Runnable {
36
+ override fun run() {
37
+ thread {
38
+ val helper = TelemetryHelper(this@MainActivity)
39
+ val active = try { helper.getActiveSensors() } catch(e:Exception){ emptyList() }
40
+ for (sensor in active) {
41
+ val key = sensor.packageName + sensor.sensor
42
+ if (!alreadyAlerted.contains(key)) {
43
+ alreadyAlerted.add(key)
44
+ val intent = Intent(this@MainActivity, OverlayService::class.java)
45
+ intent.action = OverlayService.ACTION_SHOW_SENSOR_ALERT
46
+ intent.putExtra("appName", sensor.appName)
47
+ intent.putExtra("sensor", sensor.sensor)
48
+ intent.putExtra("packageName", sensor.packageName)
49
+ startService(intent)
50
+ }
51
+ }
52
+ }
53
+ sensorMonitorHandler.postDelayed(this, 60000L)
54
+ }
55
+ }
56
+
57
+ private val clearDedupHandler = Handler(Looper.getMainLooper())
58
+ private val clearDedupRunnable = object : Runnable {
59
+ override fun run() {
60
+ alreadyAlerted.clear()
61
+ clearDedupHandler.postDelayed(this, 600_000L)
62
+ }
63
+ }
64
+
65
+ override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
66
+ super.configureFlutterEngine(flutterEngine)
67
+
68
+ // ── Accessibility Channel ────────────────────────────────────
69
+ accessibilityChannel = MethodChannel(
70
+ flutterEngine.dartExecutor.binaryMessenger,
71
+ "in.inmodel.premithius/accessibility"
72
+ ).also { channel ->
73
+ channel.setMethodCallHandler { call, result ->
74
+ when (call.method) {
75
+ "isServiceEnabled" -> {
76
+ val am = getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
77
+ val enabled = am.getEnabledAccessibilityServiceList(
78
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK
79
+ ).any {
80
+ it.resolveInfo.serviceInfo.packageName == packageName &&
81
+ it.resolveInfo.serviceInfo.name.contains("PremithiusAccessibilityService")
82
+ }
83
+ result.success(enabled)
84
+ }
85
+ "launchApp" -> {
86
+ val pkg = call.argument<String>("packageName")
87
+ if (pkg != null) {
88
+ val intent = packageManager.getLaunchIntentForPackage(pkg)
89
+ if (intent != null) startActivity(intent)
90
+ }
91
+ result.success(null)
92
+ }
93
+ else -> result.notImplemented()
94
+ }
95
+ }
96
+ }
97
+
98
+ // ── Auth Channel ─────────────────────────────────────────────
99
+ authChannel = MethodChannel(
100
+ flutterEngine.dartExecutor.binaryMessenger,
101
+ "in.inmodel.premithius/auth"
102
+ )
103
+ // Dart side sets the handler; Kotlin side may invoke methods on it
104
+
105
+ // ── Installed Apps Channel ───────────────────────────────────
106
+ MethodChannel(
107
+ flutterEngine.dartExecutor.binaryMessenger,
108
+ "in.inmodel.premithius/apps"
109
+ ).setMethodCallHandler { call, result ->
110
+ if (call.method == "getInstalledApps") {
111
+ val pm = packageManager
112
+ val apps = pm.getInstalledApplications(PackageManager.GET_META_DATA)
113
+ .filter { app ->
114
+ // Only user-installed apps OR system apps that have a launcher intent
115
+ (app.flags and ApplicationInfo.FLAG_SYSTEM) == 0 ||
116
+ pm.getLaunchIntentForPackage(app.packageName) != null
117
+ }
118
+ .filter { it.packageName != "in.inmodel.premithus" }
119
+ .map { app ->
120
+ mapOf(
121
+ "packageName" to app.packageName,
122
+ "appName" to pm.getApplicationLabel(app).toString()
123
+ )
124
+ }
125
+ result.success(apps)
126
+ } else {
127
+ result.notImplemented()
128
+ }
129
+ }
130
+ // ── VPN Channel ──────────────────────────────────────────────
131
+ MethodChannel(
132
+ flutterEngine.dartExecutor.binaryMessenger,
133
+ "in.inmodel.premithius/vpn"
134
+ ).setMethodCallHandler { call, result ->
135
+ when (call.method) {
136
+ "startVpn" -> {
137
+ val vpnIntent = VpnService.prepare(this)
138
+ if (vpnIntent != null) {
139
+ startActivityForResult(vpnIntent, VPN_REQUEST_CODE)
140
+ pendingVpnResult = result
141
+ } else {
142
+ val intent = Intent(this, KavachaVpnService::class.java)
143
+ intent.action = KavachaVpnService.ACTION_START
144
+ startService(intent)
145
+ result.success("started")
146
+ }
147
+ }
148
+ "stopVpn" -> {
149
+ val intent = Intent(this, KavachaVpnService::class.java)
150
+ intent.action = KavachaVpnService.ACTION_STOP
151
+ startService(intent)
152
+ result.success("stopped")
153
+ }
154
+ "getLastEvent" -> {
155
+ val prefs = getSharedPreferences("vpn_events", Context.MODE_PRIVATE)
156
+ result.success(prefs.getString("last_event", null))
157
+ }
158
+ "reloadBlocklist" -> {
159
+ val intent = Intent(this, KavachaVpnService::class.java)
160
+ intent.action = "ACTION_RELOAD_BLOCKLIST"
161
+ startService(intent)
162
+ result.success(null)
163
+ }
164
+ else -> result.notImplemented()
165
+ }
166
+ }
167
+
168
+ // ── Telemetry Channel ─────────────────────────────────────────
169
+ MethodChannel(
170
+ flutterEngine.dartExecutor.binaryMessenger,
171
+ "in.inmodel.premithius/telemetry"
172
+ ).setMethodCallHandler { call, result ->
173
+ val helper = TelemetryHelper(this@MainActivity)
174
+ when (call.method) {
175
+ "hasUsagePermission" -> result.success(helper.hasUsageStatsPermission())
176
+ "getPrivacyStories" -> {
177
+ thread {
178
+ val sensors = try { helper.getActiveSensors() } catch(e:Exception){ emptyList() }
179
+ val perms = try { helper.getPermissionStats() } catch(e:Exception){ emptyList() }
180
+ val data = try { helper.getSleepTimeDataUsage() } catch(e:Exception){ emptyList() }
181
+ val stories = helper.generatePrivacyStories(sensors, perms, data)
182
+ val jsonArray = JSONArray()
183
+ for (s in stories) {
184
+ val obj = JSONObject()
185
+ obj.put("severity", s.severity)
186
+ obj.put("emoji", s.emoji)
187
+ obj.put("english", s.english)
188
+ obj.put("hindi", s.hindi)
189
+ obj.put("packageName", s.packageName)
190
+ jsonArray.put(obj)
191
+ }
192
+ Handler(Looper.getMainLooper()).post { result.success(jsonArray.toString()) }
193
+ }
194
+ }
195
+ "getActiveSensors" -> {
196
+ thread {
197
+ val sensors = try { helper.getActiveSensors() } catch(e:Exception){ emptyList() }
198
+ val jsonArray = JSONArray()
199
+ for (s in sensors) {
200
+ val obj = JSONObject()
201
+ obj.put("packageName", s.packageName)
202
+ obj.put("appName", s.appName)
203
+ obj.put("sensor", s.sensor)
204
+ obj.put("isActive", s.isActive)
205
+ jsonArray.put(obj)
206
+ }
207
+ Handler(Looper.getMainLooper()).post { result.success(jsonArray.toString()) }
208
+ }
209
+ }
210
+ "getDataUsage" -> {
211
+ thread {
212
+ val data = try { helper.getSleepTimeDataUsage() } catch(e:Exception){ emptyList() }
213
+ val jsonArray = JSONArray()
214
+ for (d in data) {
215
+ val obj = JSONObject()
216
+ obj.put("packageName", d.packageName)
217
+ obj.put("appName", d.appName)
218
+ obj.put("bytesSent", d.bytesSent)
219
+ obj.put("mbSent", d.mbSent)
220
+ jsonArray.put(obj)
221
+ }
222
+ Handler(Looper.getMainLooper()).post { result.success(jsonArray.toString()) }
223
+ }
224
+ }
225
+ "getPermissionStats" -> {
226
+ thread {
227
+ val perms = try { helper.getPermissionStats() } catch(e:Exception){ emptyList() }
228
+ val jsonArray = JSONArray()
229
+ for (p in perms) {
230
+ val obj = JSONObject()
231
+ obj.put("packageName", p.packageName)
232
+ obj.put("appName", p.appName)
233
+ val counts = JSONObject()
234
+ for ((k, v) in p.accessCounts) { counts.put(k, v) }
235
+ obj.put("accessCounts", counts)
236
+ obj.put("isSystemApp", p.isSystemApp)
237
+ jsonArray.put(obj)
238
+ }
239
+ Handler(Looper.getMainLooper()).post { result.success(jsonArray.toString()) }
240
+ }
241
+ }
242
+ else -> result.notImplemented()
243
+ }
244
+ }
245
+ }
246
+
247
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
248
+ if (requestCode == VPN_REQUEST_CODE) {
249
+ if (resultCode == RESULT_OK) {
250
+ val intent = Intent(this, KavachaVpnService::class.java)
251
+ intent.action = KavachaVpnService.ACTION_START
252
+ startService(intent)
253
+ pendingVpnResult?.success("started")
254
+ } else {
255
+ pendingVpnResult?.success("denied")
256
+ }
257
+ pendingVpnResult = null
258
+ }
259
+ super.onActivityResult(requestCode, resultCode, data)
260
+ }
261
+
262
+ override fun onCreate(savedInstanceState: Bundle?) {
263
+ super.onCreate(savedInstanceState)
264
+ sensorMonitorHandler.post(sensorMonitorRunnable)
265
+ clearDedupHandler.postDelayed(clearDedupRunnable, 600000L)
266
+ }
267
+
268
+ override fun onDestroy() {
269
+ super.onDestroy()
270
+ sensorMonitorHandler.removeCallbacksAndMessages(null)
271
+ clearDedupHandler.removeCallbacksAndMessages(null)
272
+ }
273
+ }
android/app/src/main/kotlin/in/inmodel/premithus/OverlayService.kt ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.app.Service
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.graphics.Color
7
+ import android.graphics.PixelFormat
8
+ import android.os.Handler
9
+ import android.os.IBinder
10
+ import android.os.Looper
11
+ import android.view.Gravity
12
+ import android.view.ViewGroup
13
+ import android.view.WindowManager
14
+ import android.widget.Button
15
+ import android.widget.LinearLayout
16
+ import android.widget.TextView
17
+ import io.flutter.FlutterInjector
18
+ import io.flutter.embedding.engine.FlutterEngine
19
+ import io.flutter.embedding.engine.dart.DartExecutor
20
+ import io.flutter.plugin.common.MethodChannel
21
+
22
+ class OverlayService : Service() {
23
+
24
+ companion object {
25
+ const val ACTION_SHOW_AUTH = "ACTION_SHOW_AUTH"
26
+ const val ACTION_SHOW_DOMAIN_BLOCK = "ACTION_SHOW_DOMAIN_BLOCK"
27
+ const val ACTION_SHOW_SENSOR_ALERT = "ACTION_SHOW_SENSOR_ALERT"
28
+ }
29
+
30
+ private lateinit var windowManager: WindowManager
31
+ private var overlayView: LinearLayout? = null
32
+ private var authOverlayView: LinearLayout? = null
33
+ private var autoDismissHandler: Handler? = null
34
+
35
+ // Background single engine for scam analysis
36
+ private lateinit var flutterEngine: FlutterEngine
37
+ private lateinit var methodChannel: MethodChannel
38
+ private val CHANNEL = "in.inmodel.premithus/scam"
39
+
40
+ override fun onCreate() {
41
+ super.onCreate()
42
+ windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
43
+
44
+ flutterEngine = FlutterEngine(this)
45
+ flutterEngine.dartExecutor.executeDartEntrypoint(
46
+ DartExecutor.DartEntrypoint(
47
+ FlutterInjector.instance().flutterLoader().findAppBundlePath(),
48
+ "scamMain"
49
+ )
50
+ )
51
+ methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
52
+ }
53
+
54
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
55
+ if (intent?.action == "in.inmodel.premithus.ACTION_ANALYZE_SMS") {
56
+ val sender = intent.getStringExtra("sender") ?: ""
57
+ val messageBody = intent.getStringExtra("messageBody") ?: ""
58
+
59
+ val params = mapOf("sender" to sender, "messageBody" to messageBody)
60
+
61
+ methodChannel.invokeMethod("analyze", params, object : MethodChannel.Result {
62
+ override fun success(result: Any?) {
63
+ val map = result as? Map<String, Any> ?: return
64
+ val isScam = map["isScam"] as? Boolean ?: false
65
+ val category = map["category"] as? String ?: "Unknown"
66
+ val layerLabel = map["layerLabel"] as? String ?: ""
67
+ if (isScam) {
68
+ showOverlay(sender, messageBody, category, layerLabel)
69
+ }
70
+ }
71
+ override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {}
72
+ override fun notImplemented() {}
73
+ })
74
+ }
75
+
76
+ if (intent?.action == ACTION_SHOW_AUTH) {
77
+ val packageName = intent.getStringExtra("package_name") ?: return START_STICKY
78
+ val appName = intent.getStringExtra("app_name") ?: packageName
79
+ showAuthOverlay(packageName, appName)
80
+ }
81
+
82
+ if (intent?.action == ACTION_SHOW_DOMAIN_BLOCK) {
83
+ val domain = intent.getStringExtra("domain") ?: ""
84
+ val category = intent.getStringExtra("category") ?: ""
85
+ showDomainBlockOverlay(domain, category)
86
+ }
87
+
88
+ if (intent?.action == ACTION_SHOW_SENSOR_ALERT) {
89
+ val appName = intent.getStringExtra("appName") ?: ""
90
+ val sensor = intent.getStringExtra("sensor") ?: ""
91
+ val packageName = intent.getStringExtra("packageName") ?: ""
92
+ showSensorOverlay(appName, sensor, packageName)
93
+ }
94
+
95
+ return START_STICKY
96
+ }
97
+
98
+ private fun showAuthOverlay(packageName: String, appName: String) {
99
+ // Dismiss any existing auth overlay
100
+ authOverlayView?.let {
101
+ try { windowManager.removeView(it) } catch (e: Exception) {}
102
+ }
103
+ autoDismissHandler?.removeCallbacksAndMessages(null)
104
+
105
+ authOverlayView = LinearLayout(this).apply {
106
+ orientation = LinearLayout.VERTICAL
107
+ setBackgroundColor(android.graphics.Color.parseColor("#1A1A2E"))
108
+ setPadding(40, 48, 40, 48)
109
+
110
+ val titleView = android.widget.TextView(context).apply {
111
+ text = "\uD83D\uDD12 App Locked — $appName"
112
+ setTextColor(android.graphics.Color.WHITE)
113
+ textSize = 18f
114
+ setTypeface(null, android.graphics.Typeface.BOLD)
115
+ }
116
+ addView(titleView)
117
+
118
+ val subtitleView = android.widget.TextView(context).apply {
119
+ text = "Authenticate to open"
120
+ setTextColor(android.graphics.Color.parseColor("#AAAACC"))
121
+ textSize = 14f
122
+ setPadding(0, 8, 0, 24)
123
+ }
124
+ addView(subtitleView)
125
+
126
+ val buttonLayout = LinearLayout(context).apply {
127
+ orientation = LinearLayout.HORIZONTAL
128
+
129
+ val biometricBtn = android.widget.Button(context).apply {
130
+ text = "Use Biometrics"
131
+ setTextColor(android.graphics.Color.WHITE)
132
+ setBackgroundColor(android.graphics.Color.parseColor("#6C63FF"))
133
+ layoutParams = LinearLayout.LayoutParams(
134
+ 0, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 1f
135
+ ).apply { setMargins(0, 0, 8, 0) }
136
+ setOnClickListener {
137
+ // Send biometric auth request to Flutter via MainActivity channel
138
+ Handler(Looper.getMainLooper()).post {
139
+ val args = mapOf("packageName" to packageName, "appName" to appName)
140
+ MainActivity.authChannel?.invokeMethod("requestBiometricAuth", args)
141
+ }
142
+ dismissAuthOverlay()
143
+ }
144
+ }
145
+
146
+ val cancelBtn = android.widget.Button(context).apply {
147
+ text = "Cancel"
148
+ setTextColor(android.graphics.Color.WHITE)
149
+ setBackgroundColor(android.graphics.Color.parseColor("#444466"))
150
+ layoutParams = LinearLayout.LayoutParams(
151
+ 0, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 1f
152
+ ).apply { setMargins(8, 0, 0, 0) }
153
+ setOnClickListener { dismissAuthOverlay() }
154
+ }
155
+
156
+ addView(biometricBtn)
157
+ addView(cancelBtn)
158
+ }
159
+ addView(buttonLayout)
160
+ }
161
+
162
+ val params = android.view.WindowManager.LayoutParams(
163
+ android.view.WindowManager.LayoutParams.MATCH_PARENT,
164
+ android.view.WindowManager.LayoutParams.WRAP_CONTENT,
165
+ android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
166
+ android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
167
+ android.graphics.PixelFormat.TRANSLUCENT
168
+ ).apply {
169
+ gravity = android.view.Gravity.TOP
170
+ y = 100
171
+ }
172
+
173
+ windowManager.addView(authOverlayView, params)
174
+
175
+ // Auto dismiss after 15 seconds
176
+ autoDismissHandler = Handler(Looper.getMainLooper())
177
+ autoDismissHandler!!.postDelayed({ dismissAuthOverlay() }, 15_000)
178
+ }
179
+
180
+ private fun dismissAuthOverlay() {
181
+ autoDismissHandler?.removeCallbacksAndMessages(null)
182
+ authOverlayView?.let {
183
+ try { windowManager.removeView(it) } catch (e: Exception) {}
184
+ authOverlayView = null
185
+ }
186
+ }
187
+
188
+ private fun showOverlay(sender: String, message: String, category: String, layerLabel: String = "") {
189
+ if (overlayView != null) {
190
+ windowManager.removeView(overlayView)
191
+ }
192
+
193
+ overlayView = LinearLayout(this).apply {
194
+ orientation = LinearLayout.VERTICAL
195
+ setBackgroundColor(Color.parseColor("#E53935")) // Red background
196
+ setPadding(32, 32, 32, 32)
197
+
198
+ val titleView = TextView(context).apply {
199
+ text = "HIGH RISK — $category"
200
+ setTextColor(Color.WHITE)
201
+ textSize = 18f
202
+ setTypeface(null, android.graphics.Typeface.BOLD)
203
+ }
204
+
205
+ val previewView = TextView(context).apply {
206
+ text = "$sender: ${message.take(60)}..."
207
+ setTextColor(Color.WHITE)
208
+ textSize = 14f
209
+ setPadding(0, 8, 0, 0)
210
+ }
211
+
212
+ addView(titleView)
213
+
214
+ if (layerLabel.isNotEmpty()) {
215
+ val caughtByView = TextView(context).apply {
216
+ text = "\uD83D\uDEE1\uFE0F Caught by: $layerLabel"
217
+ setTextColor(Color.parseColor("#FFCDD2"))
218
+ textSize = 12f
219
+ setPadding(0, 4, 0, 0)
220
+ }
221
+ addView(caughtByView)
222
+ }
223
+ addView(previewView)
224
+
225
+ val buttonLayout = LinearLayout(context).apply {
226
+ orientation = LinearLayout.HORIZONTAL
227
+ setPadding(0, 32, 0, 0)
228
+
229
+ val confirmBtn = Button(context).apply {
230
+ text = "Confirm Scam"
231
+ setTextColor(Color.WHITE)
232
+ setBackgroundColor(Color.parseColor("#B71C1C"))
233
+ layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply {
234
+ setMargins(0, 0, 8, 0)
235
+ }
236
+ setOnClickListener {
237
+ val params = mapOf("sender" to sender, "messageBody" to message, "isScam" to true)
238
+ methodChannel.invokeMethod("feedback", params)
239
+ windowManager.removeView(overlayView)
240
+ overlayView = null
241
+ }
242
+ }
243
+
244
+ val safeBtn = Button(context).apply {
245
+ text = "Not a Scam"
246
+ setTextColor(Color.WHITE)
247
+ setBackgroundColor(Color.parseColor("#43A047"))
248
+ layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply {
249
+ setMargins(8, 0, 0, 0)
250
+ }
251
+ setOnClickListener {
252
+ val params = mapOf("sender" to sender, "messageBody" to message, "isScam" to false)
253
+ methodChannel.invokeMethod("feedback", params)
254
+ windowManager.removeView(overlayView)
255
+ overlayView = null
256
+ }
257
+ }
258
+
259
+ addView(confirmBtn)
260
+ addView(safeBtn)
261
+ }
262
+ addView(buttonLayout)
263
+
264
+ setOnClickListener {
265
+ windowManager.removeView(overlayView)
266
+ overlayView = null
267
+ }
268
+ }
269
+
270
+ val params = WindowManager.LayoutParams(
271
+ WindowManager.LayoutParams.MATCH_PARENT,
272
+ WindowManager.LayoutParams.WRAP_CONTENT,
273
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
274
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
275
+ PixelFormat.TRANSLUCENT
276
+ ).apply {
277
+ gravity = Gravity.TOP
278
+ y = 50 // small inset
279
+ }
280
+
281
+ windowManager.addView(overlayView, params)
282
+
283
+ // Auto dismiss after 8 seconds
284
+ Handler(Looper.getMainLooper()).postDelayed({
285
+ if (overlayView != null) {
286
+ windowManager.removeView(overlayView)
287
+ overlayView = null
288
+ }
289
+ }, 8000)
290
+
291
+ // Force widget refresh whenever a scam SMS is detected
292
+ try {
293
+ PremithiusWidget.forceRefresh(applicationContext)
294
+ } catch(e: Exception) {}
295
+ }
296
+
297
+ private fun showDomainBlockOverlay(domain: String, category: String) {
298
+ if (overlayView != null) {
299
+ windowManager.removeView(overlayView)
300
+ }
301
+
302
+ overlayView = LinearLayout(this).apply {
303
+ orientation = LinearLayout.VERTICAL
304
+ setBackgroundColor(Color.parseColor("#E53935")) // Red background
305
+ setPadding(32, 32, 32, 32)
306
+
307
+ val titleView = TextView(context).apply {
308
+ text = "Scam Domain Blocked"
309
+ setTextColor(Color.WHITE)
310
+ textSize = 18f
311
+ setTypeface(null, android.graphics.Typeface.BOLD)
312
+ }
313
+
314
+ val caughtByView = TextView(context).apply {
315
+ text = "\uD83D\uDEE1\uFE0F Caught by: Kavacha VPN Shield"
316
+ setTextColor(Color.parseColor("#FFCDD2"))
317
+ textSize = 12f
318
+ setPadding(0, 4, 0, 8)
319
+ }
320
+
321
+ val subtitleView = TextView(context).apply {
322
+ text = domain
323
+ setTextColor(Color.WHITE)
324
+ textSize = 16f
325
+ setTypeface(null, android.graphics.Typeface.BOLD)
326
+ }
327
+
328
+ val detailView = TextView(context).apply {
329
+ text = category
330
+ setTextColor(Color.parseColor("#FFCDD2"))
331
+ textSize = 14f
332
+ setPadding(0, 4, 0, 0)
333
+ }
334
+
335
+ addView(titleView)
336
+ addView(caughtByView)
337
+ addView(subtitleView)
338
+ addView(detailView)
339
+
340
+ val buttonLayout = LinearLayout(context).apply {
341
+ orientation = LinearLayout.HORIZONTAL
342
+ setPadding(0, 32, 0, 0)
343
+
344
+ val detailsBtn = Button(context).apply {
345
+ text = "View Details"
346
+ setTextColor(Color.WHITE)
347
+ setBackgroundColor(Color.parseColor("#B71C1C"))
348
+ layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply {
349
+ setMargins(0, 0, 8, 0)
350
+ }
351
+ setOnClickListener {
352
+ val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
353
+ if (launchIntent != null) {
354
+ launchIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
355
+ startActivity(launchIntent)
356
+ }
357
+ windowManager.removeView(overlayView)
358
+ overlayView = null
359
+ }
360
+ }
361
+
362
+ val dismissBtn = Button(context).apply {
363
+ text = "Dismiss"
364
+ setTextColor(Color.WHITE)
365
+ setBackgroundColor(Color.parseColor("#444466"))
366
+ layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply {
367
+ setMargins(8, 0, 0, 0)
368
+ }
369
+ setOnClickListener {
370
+ windowManager.removeView(overlayView)
371
+ overlayView = null
372
+ }
373
+ }
374
+
375
+ addView(detailsBtn)
376
+ addView(dismissBtn)
377
+ }
378
+ addView(buttonLayout)
379
+ }
380
+
381
+ val params = WindowManager.LayoutParams(
382
+ WindowManager.LayoutParams.MATCH_PARENT,
383
+ WindowManager.LayoutParams.WRAP_CONTENT,
384
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
385
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
386
+ PixelFormat.TRANSLUCENT
387
+ ).apply {
388
+ gravity = Gravity.TOP
389
+ y = 50 // small inset
390
+ }
391
+
392
+ windowManager.addView(overlayView, params)
393
+
394
+ // Auto dismiss after 6 seconds
395
+ Handler(Looper.getMainLooper()).postDelayed({
396
+ if (overlayView != null) {
397
+ windowManager.removeView(overlayView)
398
+ overlayView = null
399
+ }
400
+ }, 6000)
401
+
402
+ // Force widget refresh whenever a domain is blocked
403
+ try {
404
+ PremithiusWidget.forceRefresh(applicationContext)
405
+ } catch(e: Exception) {}
406
+ }
407
+
408
+ private fun showSensorOverlay(appName: String, sensor: String, packageName: String) {
409
+ if (overlayView != null) {
410
+ windowManager.removeView(overlayView)
411
+ }
412
+
413
+ overlayView = LinearLayout(this).apply {
414
+ orientation = LinearLayout.VERTICAL
415
+ setBackgroundColor(Color.parseColor("#FFCC7700")) // Orange background for sensor alert
416
+ setPadding(32, 32, 32, 32)
417
+
418
+ val titleView = TextView(context).apply {
419
+ text = "${sensor.capitalize()} active in background"
420
+ setTextColor(Color.WHITE)
421
+ textSize = 18f
422
+ setTypeface(null, android.graphics.Typeface.BOLD)
423
+ }
424
+
425
+ val caughtByView = TextView(context).apply {
426
+ text = "\uD83D\uDEE1\uFE0F Caught by: Data Shield"
427
+ setTextColor(Color.parseColor("#FFE0B2"))
428
+ textSize = 12f
429
+ setPadding(0, 4, 0, 8)
430
+ }
431
+
432
+ val subtitleView = TextView(context).apply {
433
+ text = "$appName is using your $sensor right now"
434
+ setTextColor(Color.WHITE)
435
+ textSize = 16f
436
+ }
437
+
438
+ addView(titleView)
439
+ addView(caughtByView)
440
+ addView(subtitleView)
441
+
442
+ val buttonLayout = LinearLayout(context).apply {
443
+ orientation = LinearLayout.HORIZONTAL
444
+ setPadding(0, 32, 0, 0)
445
+
446
+ val detailsBtn = Button(context).apply {
447
+ text = "Open Data Shield"
448
+ setTextColor(Color.WHITE)
449
+ setBackgroundColor(Color.parseColor("#E65100"))
450
+ layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply {
451
+ setMargins(0, 0, 8, 0)
452
+ }
453
+ setOnClickListener {
454
+ val launchIntent = packageManager.getLaunchIntentForPackage(context.packageName)
455
+ if (launchIntent != null) {
456
+ launchIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
457
+ startActivity(launchIntent)
458
+ }
459
+ windowManager.removeView(overlayView)
460
+ overlayView = null
461
+ }
462
+ }
463
+
464
+ val dismissBtn = Button(context).apply {
465
+ text = "Dismiss"
466
+ setTextColor(Color.WHITE)
467
+ setBackgroundColor(Color.parseColor("#444466"))
468
+ layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f).apply {
469
+ setMargins(8, 0, 0, 0)
470
+ }
471
+ setOnClickListener {
472
+ windowManager.removeView(overlayView)
473
+ overlayView = null
474
+ }
475
+ }
476
+
477
+ addView(detailsBtn)
478
+ addView(dismissBtn)
479
+ }
480
+ addView(buttonLayout)
481
+ }
482
+
483
+ val params = WindowManager.LayoutParams(
484
+ WindowManager.LayoutParams.MATCH_PARENT,
485
+ WindowManager.LayoutParams.WRAP_CONTENT,
486
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
487
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
488
+ PixelFormat.TRANSLUCENT
489
+ ).apply {
490
+ gravity = Gravity.TOP
491
+ y = 50 // small inset
492
+ }
493
+
494
+ windowManager.addView(overlayView, params)
495
+
496
+ // Auto dismiss after 8 seconds
497
+ Handler(Looper.getMainLooper()).postDelayed({
498
+ if (overlayView != null) {
499
+ windowManager.removeView(overlayView)
500
+ overlayView = null
501
+ }
502
+ }, 8000)
503
+ }
504
+
505
+ override fun onBind(intent: Intent?): IBinder? = null
506
+
507
+ override fun onDestroy() {
508
+ super.onDestroy()
509
+ flutterEngine.destroy()
510
+ if (overlayView != null) {
511
+ try { windowManager.removeView(overlayView) } catch (e: Exception) {}
512
+ }
513
+ dismissAuthOverlay()
514
+ }
515
+ }
android/app/src/main/kotlin/in/inmodel/premithus/PremithiusAccessibilityService.kt ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.accessibilityservice.AccessibilityService
4
+ import android.accessibilityservice.AccessibilityServiceInfo
5
+ import android.content.Intent
6
+ import android.os.Handler
7
+ import android.os.Looper
8
+ import android.util.Log
9
+ import android.view.accessibility.AccessibilityEvent
10
+
11
+ class PremithiusAccessibilityService : AccessibilityService() {
12
+
13
+ companion object {
14
+ // Shared state — readable from other Kotlin classes
15
+ var foregroundPackage: String = ""
16
+ var foregroundAppName: String = ""
17
+ var isServiceRunning: Boolean = false
18
+
19
+ // MethodChannel name for Flutter communication
20
+ const val CHANNEL = "in.inmodel.premithius/accessibility"
21
+ }
22
+
23
+ override fun onServiceConnected() {
24
+ isServiceRunning = true
25
+ // Configure which events to listen for
26
+ val info = AccessibilityServiceInfo()
27
+ info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED or
28
+ AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
29
+ info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC
30
+ info.flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS or
31
+ AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS
32
+ info.notificationTimeout = 100
33
+ serviceInfo = info
34
+ Log.d("PremithiusA11y", "Service connected")
35
+ }
36
+
37
+ override fun onAccessibilityEvent(event: AccessibilityEvent) {
38
+ if (event.eventType != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) return
39
+
40
+ val packageName = event.packageName?.toString() ?: return
41
+ if (packageName == foregroundPackage) return // same app, ignore
42
+ if (packageName == "in.inmodel.premithus") return // ignore ourselves
43
+
44
+ foregroundPackage = packageName
45
+ foregroundAppName = getAppName(packageName)
46
+
47
+ Log.d("PremithiusA11y", "Foreground: $packageName")
48
+
49
+ // Feature 1: App Lock check
50
+ checkAppLock(packageName)
51
+
52
+ // Feature 2: Notify Flutter of foreground context
53
+ // (used by keyboard tone switching + OTP verification)
54
+ notifyFlutter(packageName, foregroundAppName)
55
+ }
56
+
57
+ override fun onInterrupt() {
58
+ isServiceRunning = false
59
+ }
60
+
61
+ // ── Feature 1: App Lock ──────────────────────────────────────
62
+ private fun checkAppLock(packageName: String) {
63
+ // Query locked_apps SQLite table via PremithiusDatabase
64
+ // Run on background thread — never block accessibility thread
65
+ Thread {
66
+ val isLocked = PremithiusDatabase.getInstance(this)
67
+ .lockedAppDao()
68
+ .isLocked(packageName)
69
+
70
+ if (isLocked) {
71
+ Log.d("PremithiusA11y", "LOCKED APP DETECTED: $packageName")
72
+
73
+ // Step 1: Immediately go home — app never shows
74
+ performGlobalAction(GLOBAL_ACTION_HOME)
75
+
76
+ // Step 2: Show auth overlay via OverlayService
77
+ val intent = Intent(this, OverlayService::class.java)
78
+ intent.action = OverlayService.ACTION_SHOW_AUTH
79
+ intent.putExtra("package_name", packageName)
80
+ intent.putExtra("app_name", foregroundAppName)
81
+ startService(intent)
82
+
83
+ // Step 3: Log access attempt
84
+ PremithiusDatabase.getInstance(this)
85
+ .lockedAppDao()
86
+ .logAccessAttempt(packageName, System.currentTimeMillis())
87
+ }
88
+ }.start()
89
+ }
90
+
91
+ // ── Feature 2: Notify Flutter ────────────────────────────────
92
+ private fun notifyFlutter(packageName: String, appName: String) {
93
+ // Send foreground context to Flutter via MethodChannel
94
+ val context = mapOf(
95
+ "package" to packageName,
96
+ "appName" to appName,
97
+ "toneContext" to getToneContext(packageName)
98
+ )
99
+ // Post to main thread for MethodChannel call
100
+ Handler(Looper.getMainLooper()).post {
101
+ MainActivity.accessibilityChannel?.invokeMethod("onForegroundChanged", context)
102
+ }
103
+ }
104
+
105
+ // ── Tone context mapping ─────────────────────────────────────
106
+ private fun getToneContext(packageName: String): String {
107
+ return when {
108
+ packageName.contains("whatsapp") ||
109
+ packageName.contains("telegram") ||
110
+ packageName.contains("signal") -> "casual"
111
+
112
+ packageName.contains("gmail") ||
113
+ packageName.contains("outlook") ||
114
+ packageName.contains("yahoo.mail") -> "formal"
115
+
116
+ packageName.contains("linkedin") -> "professional"
117
+
118
+ packageName.contains("twitter") ||
119
+ packageName.contains("instagram") -> "casual"
120
+
121
+ else -> "neutral"
122
+ }
123
+ }
124
+
125
+ // ── Helper: get human-readable app name ─────────────────────
126
+ private fun getAppName(packageName: String): String {
127
+ return try {
128
+ val pm = packageManager
129
+ val appInfo = pm.getApplicationInfo(packageName, 0)
130
+ pm.getApplicationLabel(appInfo).toString()
131
+ } catch (e: Exception) {
132
+ packageName
133
+ }
134
+ }
135
+ }
android/app/src/main/kotlin/in/inmodel/premithus/PremithiusDatabase.kt ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.content.Context
4
+ import android.database.sqlite.SQLiteDatabase
5
+ import android.database.sqlite.SQLiteOpenHelper
6
+
7
+ class PremithiusDatabase private constructor(context: Context)
8
+ : SQLiteOpenHelper(context, "premithius.db", null, 2) {
9
+
10
+ companion object {
11
+ @Volatile private var INSTANCE: PremithiusDatabase? = null
12
+
13
+ fun getInstance(context: Context): PremithiusDatabase {
14
+ return INSTANCE ?: synchronized(this) {
15
+ INSTANCE ?: PremithiusDatabase(context.applicationContext).also { INSTANCE = it }
16
+ }
17
+ }
18
+ }
19
+
20
+ override fun onCreate(db: SQLiteDatabase) {
21
+ // Tables created by Flutter (sqflite) — we just add new ones here
22
+ db.execSQL("""
23
+ CREATE TABLE IF NOT EXISTS locked_apps (
24
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
25
+ package_name TEXT UNIQUE NOT NULL,
26
+ app_name TEXT NOT NULL,
27
+ auth_method TEXT DEFAULT 'biometric',
28
+ locked_at INTEGER NOT NULL,
29
+ access_attempts INTEGER DEFAULT 0,
30
+ temporary_unlock_until INTEGER DEFAULT 0
31
+ )
32
+ """.trimIndent())
33
+
34
+ db.execSQL("""
35
+ CREATE TABLE IF NOT EXISTS access_log (
36
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
37
+ package_name TEXT NOT NULL,
38
+ app_name TEXT,
39
+ was_allowed INTEGER DEFAULT 0,
40
+ attempted_at INTEGER NOT NULL
41
+ )
42
+ """.trimIndent())
43
+ }
44
+
45
+ override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
46
+ if (oldVersion < 2) {
47
+ db.execSQL("""
48
+ CREATE TABLE IF NOT EXISTS locked_apps (
49
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
50
+ package_name TEXT UNIQUE NOT NULL,
51
+ app_name TEXT NOT NULL,
52
+ auth_method TEXT DEFAULT 'biometric',
53
+ locked_at INTEGER NOT NULL,
54
+ access_attempts INTEGER DEFAULT 0,
55
+ temporary_unlock_until INTEGER DEFAULT 0
56
+ )
57
+ """.trimIndent())
58
+
59
+ db.execSQL("""
60
+ CREATE TABLE IF NOT EXISTS access_log (
61
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
62
+ package_name TEXT NOT NULL,
63
+ app_name TEXT,
64
+ was_allowed INTEGER DEFAULT 0,
65
+ attempted_at INTEGER NOT NULL
66
+ )
67
+ """.trimIndent())
68
+ }
69
+ }
70
+
71
+ fun lockedAppDao(): LockedAppDao = LockedAppDao(writableDatabase)
72
+
73
+ fun scamLogDao() = ScamLogDao(writableDatabase)
74
+ fun scamDomainDao() = ScamDomainDao(writableDatabase)
75
+
76
+ class ScamLogDao(private val db: SQLiteDatabase) {
77
+ fun getCountSince(timestamp: Long): Int {
78
+ val cursor = db.rawQuery("SELECT COUNT(*) FROM scam_log WHERE created_at >= ?", arrayOf(timestamp.toString()))
79
+ var count = 0
80
+ if (cursor.moveToFirst()) {
81
+ count = cursor.getInt(0)
82
+ }
83
+ cursor.close()
84
+ return count
85
+ }
86
+ }
87
+
88
+ class ScamDomainDao(private val db: SQLiteDatabase) {
89
+ fun getHitsSince(timestamp: Long): Int {
90
+ val cursor = db.rawQuery("SELECT COUNT(*) FROM vpn_events WHERE created_at >= ?", arrayOf(timestamp.toString()))
91
+ var count = 0
92
+ if (cursor.moveToFirst()) {
93
+ count = cursor.getInt(0)
94
+ }
95
+ cursor.close()
96
+ return count
97
+ }
98
+ }
99
+ }
android/app/src/main/kotlin/in/inmodel/premithus/PremithiusWidget.kt ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.app.PendingIntent
4
+ import android.appwidget.AppWidgetManager
5
+ import android.appwidget.AppWidgetProvider
6
+ import android.content.ComponentName
7
+ import android.content.Context
8
+ import android.content.Intent
9
+ import android.widget.RemoteViews
10
+
11
+ class PremithiusWidget : AppWidgetProvider() {
12
+
13
+ override fun onUpdate(
14
+ context: Context,
15
+ appWidgetManager: AppWidgetManager,
16
+ appWidgetIds: IntArray
17
+ ) {
18
+ appWidgetIds.forEach { id ->
19
+ updateWidget(context, appWidgetManager, id)
20
+ }
21
+ }
22
+
23
+ companion object {
24
+ fun updateWidget(context: Context, manager: AppWidgetManager, id: Int) {
25
+ val views = RemoteViews(context.packageName, R.layout.widget_layout)
26
+
27
+ // Read data from SQLite directly (no Flutter needed)
28
+ val db = PremithiusDatabase.getInstance(context)
29
+ val today = System.currentTimeMillis() - 86400000L
30
+
31
+ // Tile 1: Mic/Camera RIGHT NOW
32
+ val telemetry = TelemetryHelper(context)
33
+ val activeSensors = try { telemetry.getActiveSensors() } catch (e: Exception) { emptyList() }
34
+ val sensorText = if (activeSensors.isNotEmpty())
35
+ "⚠️ ${activeSensors.first().appName} active"
36
+ else "✅ No sensors active"
37
+ val sensorColor = if (activeSensors.isNotEmpty())
38
+ R.color.widget_red else R.color.widget_green
39
+ views.setTextViewText(R.id.tile_sensor, sensorText)
40
+ views.setInt(R.id.tile_sensor, "setBackgroundColor",
41
+ context.getColor(sensorColor))
42
+
43
+ // Tile 2: Data sent last night (MB)
44
+ val dataUsage = try { telemetry.getSleepTimeDataUsage() } catch (e: Exception) { emptyList() }
45
+ val totalMb = dataUsage.sumOf { it.mbSent }.toInt()
46
+ val dataText = if (totalMb > 0) "📤 ${totalMb}MB sent" else "📤 0MB sent"
47
+ val dataColor = if (totalMb > 100) R.color.widget_red
48
+ else if (totalMb > 20) R.color.widget_amber
49
+ else R.color.widget_green
50
+ views.setTextViewText(R.id.tile_data, dataText)
51
+ views.setInt(R.id.tile_data, "setBackgroundColor",
52
+ context.getColor(dataColor))
53
+
54
+ // Tile 3: Suspicious permission spikes today
55
+ val permStats = try { telemetry.getPermissionStats(1) } catch (e: Exception) { emptyList() }
56
+ val spikeCount = permStats.count { it.totalAccesses > 5 }
57
+ val spikeText = if (spikeCount > 0) "⚠️ $spikeCount app spikes" else "✅ No spikes"
58
+ val spikeColor = if (spikeCount > 0) R.color.widget_amber else R.color.widget_green
59
+ views.setTextViewText(R.id.tile_perms, spikeText)
60
+ views.setInt(R.id.tile_perms, "setBackgroundColor",
61
+ context.getColor(spikeColor))
62
+
63
+ // Tile 4: Scam SMS + Domains blocked today (combined)
64
+ val scamCount = try { db.scamLogDao().getCountSince(today) } catch(e:Exception){ 0 }
65
+ val domainCount = try { db.scamDomainDao().getHitsSince(today) } catch(e:Exception){ 0 }
66
+ val totalBlocked = scamCount + domainCount
67
+ val blockedText = if (totalBlocked > 0)
68
+ "🚨 $totalBlocked blocked" else "✅ 0 blocked"
69
+ val blockedColor = if (totalBlocked > 0) R.color.widget_red else R.color.widget_green
70
+ views.setTextViewText(R.id.tile_blocked, blockedText)
71
+ views.setInt(R.id.tile_blocked, "setBackgroundColor",
72
+ context.getColor(blockedColor))
73
+
74
+ // Tap widget → open Premithius app
75
+ val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
76
+ if (launchIntent != null) {
77
+ val pendingIntent = PendingIntent.getActivity(
78
+ context, 0,
79
+ launchIntent,
80
+ PendingIntent.FLAG_IMMUTABLE
81
+ )
82
+ views.setOnClickPendingIntent(R.id.widget_root, pendingIntent)
83
+ }
84
+
85
+ manager.updateAppWidget(id, views)
86
+ }
87
+
88
+ fun forceRefresh(context: Context) {
89
+ val intent = Intent(context, PremithiusWidget::class.java)
90
+ intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
91
+ val ids = AppWidgetManager.getInstance(context)
92
+ .getAppWidgetIds(ComponentName(context, PremithiusWidget::class.java))
93
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
94
+ context.sendBroadcast(intent)
95
+ }
96
+ }
97
+ }
android/app/src/main/kotlin/in/inmodel/premithus/SmsReceiver.kt ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.provider.Telephony
7
+
8
+ class SmsReceiver : BroadcastReceiver() {
9
+ override fun onReceive(context: Context, intent: Intent) {
10
+ if (intent.action == Telephony.Sms.Intents.SMS_RECEIVED_ACTION) {
11
+ val messages = Telephony.Sms.Intents.getMessagesFromIntent(intent)
12
+ for (sms in messages) {
13
+ val sender = sms.displayOriginatingAddress
14
+ val messageBody = sms.messageBody
15
+
16
+ // Start OverlayService to analyze SMS using Flutter
17
+ val serviceIntent = Intent(context, OverlayService::class.java).apply {
18
+ putExtra("sender", sender)
19
+ putExtra("messageBody", messageBody)
20
+ action = "in.inmodel.premithus.ACTION_ANALYZE_SMS"
21
+ }
22
+ context.startService(serviceIntent)
23
+ }
24
+ }
25
+ }
26
+ }
android/app/src/main/kotlin/in/inmodel/premithus/TelemetryHelper.kt ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package `in`.inmodel.premithus
2
+
3
+ import android.app.AppOpsManager
4
+ import android.app.usage.NetworkStats
5
+ import android.app.usage.NetworkStatsManager
6
+ import android.app.usage.UsageStatsManager
7
+ import android.content.Context
8
+ import android.content.pm.ApplicationInfo
9
+ import android.content.pm.PackageManager
10
+ import android.net.ConnectivityManager
11
+ import android.util.Log
12
+
13
+ class TelemetryHelper(private val context: Context) {
14
+
15
+ // ── Mic/Camera real-time access ─────────────────────────────
16
+ fun getActiveSensors(): List<SensorAccess> {
17
+ val appOps = context.getSystemService(AppOpsManager::class.java)
18
+ val result = mutableListOf<SensorAccess>()
19
+
20
+ val packages = context.packageManager
21
+ .getInstalledApplications(PackageManager.GET_META_DATA)
22
+
23
+ for (app in packages) {
24
+ val micOp = appOps.unsafeCheckOpNoThrow(
25
+ AppOpsManager.OPSTR_RECORD_AUDIO,
26
+ app.uid, app.packageName
27
+ )
28
+ val camOp = appOps.unsafeCheckOpNoThrow(
29
+ AppOpsManager.OPSTR_CAMERA,
30
+ app.uid, app.packageName
31
+ )
32
+
33
+ // MODE_RUNNING = currently active (Android 10+)
34
+ if (micOp == AppOpsManager.MODE_RUNNING) {
35
+ result.add(SensorAccess(app.packageName,
36
+ getAppName(app.packageName), "microphone", true))
37
+ }
38
+ if (camOp == AppOpsManager.MODE_RUNNING) {
39
+ result.add(SensorAccess(app.packageName,
40
+ getAppName(app.packageName), "camera", true))
41
+ }
42
+ }
43
+ return result
44
+ }
45
+
46
+ // ── Permission access counts (last 7 days) ──────────────────
47
+ fun getPermissionStats(days: Int = 7): List<AppPermissionStat> {
48
+ val appOps = context.getSystemService(AppOpsManager::class.java)
49
+ val result = mutableListOf<AppPermissionStat>()
50
+ val since = System.currentTimeMillis() - (days * 86400000L)
51
+
52
+ val ops = listOf(
53
+ AppOpsManager.OPSTR_RECORD_AUDIO to "microphone",
54
+ AppOpsManager.OPSTR_CAMERA to "camera",
55
+ AppOpsManager.OPSTR_FINE_LOCATION to "location",
56
+ AppOpsManager.OPSTR_READ_CONTACTS to "contacts",
57
+ AppOpsManager.OPSTR_READ_SMS to "SMS"
58
+ )
59
+
60
+ val packages = context.packageManager
61
+ .getInstalledApplications(PackageManager.GET_META_DATA)
62
+
63
+ for (app in packages) {
64
+ val stats = mutableMapOf<String, Int>()
65
+ for ((opStr, label) in ops) {
66
+ try {
67
+ val pkgOps = appOps.getOpsForPackage(
68
+ app.uid, app.packageName, arrayOf(opStr)
69
+ )
70
+ val count = pkgOps?.firstOrNull()?.ops
71
+ ?.filter { it.time > since }
72
+ ?.size ?: 0
73
+ if (count > 0) stats[label] = count
74
+ } catch (e: Exception) { /* skip */ }
75
+ }
76
+ if (stats.isNotEmpty()) {
77
+ result.add(AppPermissionStat(
78
+ packageName = app.packageName,
79
+ appName = getAppName(app.packageName),
80
+ accessCounts = stats,
81
+ isSystemApp = (app.flags and ApplicationInfo.FLAG_SYSTEM) != 0
82
+ ))
83
+ }
84
+ }
85
+ return result.sortedByDescending { it.totalAccesses }
86
+ }
87
+
88
+ // ── Network data usage (last 24 hours) ──────────────────────
89
+ fun getSleepTimeDataUsage(): List<AppDataUsage> {
90
+ if (!hasUsageStatsPermission()) return emptyList()
91
+
92
+ val networkStats = context.getSystemService(NetworkStatsManager::class.java)
93
+
94
+ val now = System.currentTimeMillis()
95
+ val yesterday = now - 86400000L
96
+
97
+ val result = mutableListOf<AppDataUsage>()
98
+
99
+ try {
100
+ val summary = networkStats.querySummary(
101
+ ConnectivityManager.TYPE_MOBILE, null, yesterday, now
102
+ )
103
+ val bucket = NetworkStats.Bucket()
104
+ val appTotals = mutableMapOf<Int, Long>() // uid → bytes sent
105
+
106
+ while (summary.hasNextBucket()) {
107
+ summary.getNextBucket(bucket)
108
+ val uid = bucket.uid
109
+ if (uid > 1000) { // skip system UIDs
110
+ appTotals[uid] = (appTotals[uid] ?: 0) + bucket.txBytes
111
+ }
112
+ }
113
+ summary.close()
114
+
115
+ val pm = context.packageManager
116
+ for ((uid, bytes) in appTotals) {
117
+ if (bytes < 100_000) continue // skip < 100KB
118
+ try {
119
+ val pkgs = pm.getPackagesForUid(uid) ?: continue
120
+ val pkg = pkgs.first()
121
+ val appName = getAppName(pkg)
122
+ result.add(AppDataUsage(
123
+ packageName = pkg,
124
+ appName = appName,
125
+ bytesSent = bytes,
126
+ mbSent = bytes / 1_048_576.0
127
+ ))
128
+ } catch (e: Exception) { /* skip */ }
129
+ }
130
+ } catch (e: Exception) {
131
+ Log.e("TelemetryHelper", "Network stats error: ${e.message}")
132
+ }
133
+
134
+ return result.sortedByDescending { it.bytesSent }
135
+ }
136
+
137
+ // ── Story generator ─────────────────────────────────────────
138
+ fun generatePrivacyStories(
139
+ sensors: List<SensorAccess>,
140
+ permissions: List<AppPermissionStat>,
141
+ dataUsage: List<AppDataUsage>
142
+ ): List<PrivacyStory> {
143
+ val stories = mutableListOf<PrivacyStory>()
144
+
145
+ for (sensor in sensors) {
146
+ stories.add(PrivacyStory(
147
+ severity = "CRITICAL",
148
+ emoji = if (sensor.sensor == "microphone") "🎙️" else "📷",
149
+ english = "${sensor.appName} is ${sensor.sensor} RIGHT NOW",
150
+ hindi = "${sensor.appName} अभी आपका ${
151
+ if (sensor.sensor == "microphone") "माइक" else "कैमरा"
152
+ } इस्तेमाल कर रहा है",
153
+ packageName = sensor.packageName
154
+ ))
155
+ }
156
+
157
+ for (app in permissions.take(5)) {
158
+ val micCount = app.accessCounts["microphone"] ?: 0
159
+ val locCount = app.accessCounts["location"] ?: 0
160
+ val contactCount = app.accessCounts["contacts"] ?: 0
161
+
162
+ if (micCount > 10) {
163
+ stories.add(PrivacyStory(
164
+ severity = "HIGH",
165
+ emoji = "🎙️",
166
+ english = "${app.appName} accessed your microphone $micCount times this week",
167
+ hindi = "${app.appName} ने इस हफ्ते $micCount बार माइक एक्सेस किया",
168
+ packageName = app.packageName
169
+ ))
170
+ }
171
+ if (locCount > 20) {
172
+ stories.add(PrivacyStory(
173
+ severity = "HIGH",
174
+ emoji = "📍",
175
+ english = "${app.appName} tracked your location $locCount times this week",
176
+ hindi = "${app.appName} ने $locCount बार आपकी लोकेशन ट्रैक की",
177
+ packageName = app.packageName
178
+ ))
179
+ }
180
+ if (contactCount > 0 && !isCommunicationApp(app.packageName)) {
181
+ stories.add(PrivacyStory(
182
+ severity = "MEDIUM",
183
+ emoji = "👥",
184
+ english = "${app.appName} read your contacts — this app doesn't need them",
185
+ hindi = "${app.appName} ने आपके contacts पढ़े — इस app को इसकी जरूरत नहीं",
186
+ packageName = app.packageName
187
+ ))
188
+ }
189
+ }
190
+
191
+ for (app in dataUsage.take(3)) {
192
+ if (app.mbSent > 50) {
193
+ stories.add(PrivacyStory(
194
+ severity = "MEDIUM",
195
+ emoji = "📤",
196
+ english = "${app.appName} sent ${app.mbSent.toInt()} MB of your data",
197
+ hindi = "${app.appName} ने आपका ${app.mbSent.toInt()} MB डेटा भेजा",
198
+ packageName = app.packageName
199
+ ))
200
+ }
201
+ }
202
+
203
+ if (stories.isEmpty()) {
204
+ stories.add(PrivacyStory(
205
+ severity = "SAFE",
206
+ emoji = "✅",
207
+ english = "No suspicious activity detected in the last 24 hours",
208
+ hindi = "पिछले 24 घंटों में कोई संदिग्ध गतिविधि नहीं मिली",
209
+ packageName = ""
210
+ ))
211
+ }
212
+
213
+ return stories.sortedBy {
214
+ when (it.severity) { "CRITICAL" -> 0; "HIGH" -> 1; "MEDIUM" -> 2; else -> 3 }
215
+ }
216
+ }
217
+
218
+ fun hasUsageStatsPermission(): Boolean {
219
+ val appOps = context.getSystemService(AppOpsManager::class.java)
220
+ val mode = appOps.unsafeCheckOpNoThrow(
221
+ AppOpsManager.OPSTR_GET_USAGE_STATS,
222
+ android.os.Process.myUid(), context.packageName
223
+ )
224
+ return mode == AppOpsManager.MODE_ALLOWED
225
+ }
226
+
227
+ private fun getAppName(packageName: String): String {
228
+ return try {
229
+ val ai = context.packageManager.getApplicationInfo(packageName, 0)
230
+ context.packageManager.getApplicationLabel(ai).toString()
231
+ } catch (e: Exception) { packageName }
232
+ }
233
+
234
+ private fun isCommunicationApp(pkg: String): Boolean {
235
+ return pkg.contains("whatsapp") || pkg.contains("telegram") ||
236
+ pkg.contains("signal") || pkg.contains("gmail") ||
237
+ pkg.contains("message") || pkg.contains("dialer")
238
+ }
239
+ }
240
+
241
+ // Data classes
242
+ data class SensorAccess(val packageName: String, val appName: String,
243
+ val sensor: String, val isActive: Boolean)
244
+ data class AppPermissionStat(val packageName: String, val appName: String,
245
+ val accessCounts: Map<String, Int>, val isSystemApp: Boolean) {
246
+ val totalAccesses get() = accessCounts.values.sum()
247
+ }
248
+ data class AppDataUsage(val packageName: String, val appName: String,
249
+ val bytesSent: Long, val mbSent: Double)
250
+ data class PrivacyStory(val severity: String, val emoji: String,
251
+ val english: String, val hindi: String, val packageName: String)
android/app/src/main/res/drawable-v21/launch_background.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Modify this file to customize your launch splash screen -->
3
+ <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
4
+ <item android:drawable="?android:colorBackground" />
5
+
6
+ <!-- You can insert your own image assets here -->
7
+ <!-- <item>
8
+ <bitmap
9
+ android:gravity="center"
10
+ android:src="@mipmap/launch_image" />
11
+ </item> -->
12
+ </layer-list>
android/app/src/main/res/drawable/launch_background.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Modify this file to customize your launch splash screen -->
3
+ <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
4
+ <item android:drawable="@android:color/white" />
5
+
6
+ <!-- You can insert your own image assets here -->
7
+ <!-- <item>
8
+ <bitmap
9
+ android:gravity="center"
10
+ android:src="@mipmap/launch_image" />
11
+ </item> -->
12
+ </layer-list>
android/app/src/main/res/layout/widget_4x2.xml ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:layout_width="match_parent"
4
+ android:layout_height="match_parent"
5
+ android:orientation="vertical"
6
+ android:background="#2E2E2E"
7
+ android:padding="8dp">
8
+
9
+ <!-- Grid for Threat Metrics -->
10
+ <LinearLayout
11
+ android:layout_width="match_parent"
12
+ android:layout_height="wrap_content"
13
+ android:orientation="horizontal"
14
+ android:weightSum="4">
15
+
16
+ <!-- Tile 1 -->
17
+ <LinearLayout
18
+ android:id="@+id/mic_tile"
19
+ android:layout_width="0dp"
20
+ android:layout_height="wrap_content"
21
+ android:layout_weight="1"
22
+ android:orientation="vertical"
23
+ android:gravity="center"
24
+ android:padding="8dp">
25
+ <TextView android:text="MIC SPY" android:textSize="10sp" android:textColor="#888" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
26
+ <TextView android:id="@+id/mic_value" android:text="0" android:textSize="18sp" android:textStyle="bold" android:textColor="#FFF" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
27
+ </LinearLayout>
28
+
29
+ <!-- Tile 2 -->
30
+ <LinearLayout
31
+ android:layout_width="0dp"
32
+ android:layout_height="wrap_content"
33
+ android:layout_weight="1"
34
+ android:orientation="vertical"
35
+ android:gravity="center"
36
+ android:padding="8dp">
37
+ <TextView android:text="NIGHT DATA" android:textSize="10sp" android:textColor="#888" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
38
+ <TextView android:id="@+id/data_value" android:text="0 MB" android:textSize="18sp" android:textStyle="bold" android:textColor="#FFF" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
39
+ </LinearLayout>
40
+
41
+ <!-- Tile 3 -->
42
+ <LinearLayout
43
+ android:layout_width="0dp"
44
+ android:layout_height="wrap_content"
45
+ android:layout_weight="1"
46
+ android:orientation="vertical"
47
+ android:gravity="center"
48
+ android:padding="8dp">
49
+ <TextView android:text="PERMISSIONS" android:textSize="10sp" android:textColor="#888" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
50
+ <TextView android:id="@+id/perm_value" android:text="0" android:textSize="18sp" android:textStyle="bold" android:textColor="#FFF" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
51
+ </LinearLayout>
52
+
53
+ <!-- Tile 4 -->
54
+ <LinearLayout
55
+ android:layout_width="0dp"
56
+ android:layout_height="wrap_content"
57
+ android:layout_weight="1"
58
+ android:orientation="vertical"
59
+ android:gravity="center"
60
+ android:padding="8dp">
61
+ <TextView android:text="SCAMS" android:textSize="10sp" android:textColor="#888" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
62
+ <TextView android:id="@+id/scam_value" android:text="0" android:textSize="18sp" android:textStyle="bold" android:textColor="#FFF" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
63
+ </LinearLayout>
64
+ </LinearLayout>
65
+
66
+ <!-- Alert Banner -->
67
+ <LinearLayout
68
+ android:id="@+id/alert_banner"
69
+ android:layout_width="match_parent"
70
+ android:layout_height="wrap_content"
71
+ android:orientation="horizontal"
72
+ android:background="#D32F2F"
73
+ android:visibility="gone"
74
+ android:padding="8dp"
75
+ android:layout_marginTop="8dp">
76
+ <TextView
77
+ android:id="@+id/alert_text"
78
+ android:layout_width="match_parent"
79
+ android:layout_height="wrap_content"
80
+ android:text="Alert Message Here"
81
+ android:textColor="#FFFFFF"
82
+ android:textSize="12sp"
83
+ android:textStyle="bold" />
84
+ </LinearLayout>
85
+ </LinearLayout>
android/app/src/main/res/layout/widget_layout.xml ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:id="@+id/widget_root"
4
+ android:layout_width="match_parent"
5
+ android:layout_height="match_parent"
6
+ android:orientation="horizontal"
7
+ android:background="#CC1A1A2E"
8
+ android:padding="8dp">
9
+
10
+ <LinearLayout
11
+ android:layout_width="0dp"
12
+ android:layout_height="match_parent"
13
+ android:layout_weight="1"
14
+ android:orientation="vertical"
15
+ android:padding="6dp"
16
+ android:layout_marginEnd="4dp">
17
+ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="🎙️ Mic/Cam" android:textColor="#FFFFFF" android:textSize="12sp"/>
18
+ <TextView android:id="@+id/tile_sensor" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="#FFFFFF" android:textSize="14sp" android:textStyle="bold" android:layout_marginTop="4dp" android:gravity="center" android:padding="4dp"/>
19
+ </LinearLayout>
20
+
21
+ <LinearLayout
22
+ android:layout_width="0dp"
23
+ android:layout_height="match_parent"
24
+ android:layout_weight="1"
25
+ android:orientation="vertical"
26
+ android:padding="6dp"
27
+ android:layout_marginEnd="4dp">
28
+ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="📤 Data Sent" android:textColor="#FFFFFF" android:textSize="12sp"/>
29
+ <TextView android:id="@+id/tile_data" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="#FFFFFF" android:textSize="14sp" android:textStyle="bold" android:layout_marginTop="4dp" android:gravity="center" android:padding="4dp"/>
30
+ </LinearLayout>
31
+
32
+ <LinearLayout
33
+ android:layout_width="0dp"
34
+ android:layout_height="match_parent"
35
+ android:layout_weight="1"
36
+ android:orientation="vertical"
37
+ android:padding="6dp"
38
+ android:layout_marginEnd="4dp">
39
+ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="⚠️ App Spikes" android:textColor="#FFFFFF" android:textSize="12sp"/>
40
+ <TextView android:id="@+id/tile_perms" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="#FFFFFF" android:textSize="14sp" android:textStyle="bold" android:layout_marginTop="4dp" android:gravity="center" android:padding="4dp"/>
41
+ </LinearLayout>
42
+
43
+ <LinearLayout
44
+ android:layout_width="0dp"
45
+ android:layout_height="match_parent"
46
+ android:layout_weight="1"
47
+ android:orientation="vertical"
48
+ android:padding="6dp">
49
+ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="🛡️ Blocked" android:textColor="#FFFFFF" android:textSize="12sp"/>
50
+ <TextView android:id="@+id/tile_blocked" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="#FFFFFF" android:textSize="14sp" android:textStyle="bold" android:layout_marginTop="4dp" android:gravity="center" android:padding="4dp"/>
51
+ </LinearLayout>
52
+ </LinearLayout>
android/app/src/main/res/values-night/styles.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
4
+ <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
5
+ <!-- Show a splash screen on the activity. Automatically removed when
6
+ the Flutter engine draws its first frame -->
7
+ <item name="android:windowBackground">@drawable/launch_background</item>
8
+ </style>
9
+ <!-- Theme applied to the Android Window as soon as the process has started.
10
+ This theme determines the color of the Android Window while your
11
+ Flutter UI initializes, as well as behind your Flutter UI while its
12
+ running.
13
+
14
+ This Theme is only used starting with V2 of Flutter's Android embedding. -->
15
+ <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
16
+ <item name="android:windowBackground">?android:colorBackground</item>
17
+ </style>
18
+ </resources>
android/app/src/main/res/values/colors.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <color name="widget_red">#FFCC2222</color>
4
+ <color name="widget_amber">#FFCC7700</color>
5
+ <color name="widget_green">#FF227722</color>
6
+ <color name="widget_neutral">#FF333355</color>
7
+ </resources>
android/app/src/main/res/values/strings.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <string name="app_name">Premithius</string>
4
+ <string name="accessibility_label">Premithius Shield</string>
5
+ <string name="accessibility_description">Premithius uses Accessibility to detect scam apps opening and protect your privacy. No data leaves your device.</string>
6
+ <string name="accessibility_summary">App protection and scam detection</string>
7
+ <string name="widget_description">Premithius live security summary</string>
8
+ </resources>
android/app/src/main/res/values/styles.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
4
+ <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
5
+ <!-- Show a splash screen on the activity. Automatically removed when
6
+ the Flutter engine draws its first frame -->
7
+ <item name="android:windowBackground">@drawable/launch_background</item>
8
+ </style>
9
+ <!-- Theme applied to the Android Window as soon as the process has started.
10
+ This theme determines the color of the Android Window while your
11
+ Flutter UI initializes, as well as behind your Flutter UI while its
12
+ running.
13
+
14
+ This Theme is only used starting with V2 of Flutter's Android embedding. -->
15
+ <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
16
+ <item name="android:windowBackground">?android:colorBackground</item>
17
+ </style>
18
+ </resources>
android/app/src/main/res/xml/accessibility_service_config.xml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <accessibility-service
3
+ xmlns:android="http://schemas.android.com/apk/res/android"
4
+ android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
5
+ android:accessibilityFeedbackType="feedbackGeneric"
6
+ android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows"
7
+ android:canRetrieveWindowContent="true"
8
+ android:description="@string/accessibility_description"
9
+ android:notificationTimeout="100"
10
+ android:settingsActivity="in.inmodel.premithus.MainActivity"
11
+ android:summary="@string/accessibility_summary"/>
android/app/src/main/res/xml/method.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <input-method xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:supportsInlineSuggestions="true">
4
+ <subtype
5
+ android:imeSubtypeLocale="en_US"
6
+ android:imeSubtypeMode="keyboard" />
7
+ </input-method>
android/app/src/main/res/xml/premithius_widget_info.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:minWidth="250dp"
4
+ android:minHeight="110dp"
5
+ android:targetCellWidth="4"
6
+ android:targetCellHeight="2"
7
+ android:updatePeriodMillis="1800000"
8
+ android:initialLayout="@layout/widget_layout"
9
+ android:widgetCategory="home_screen"
10
+ android:resizeMode="horizontal|vertical"
11
+ android:description="@string/widget_description">
12
+ </appwidget-provider>
android/app/src/profile/AndroidManifest.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <!-- The INTERNET permission is required for development. Specifically,
3
+ the Flutter tool needs it to communicate with the running application
4
+ to allow setting breakpoints, to provide hot reload, etc.
5
+ -->
6
+ <uses-permission android:name="android.permission.INTERNET"/>
7
+ </manifest>
android/build.gradle.kts ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ allprojects {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ maven { url = uri("https://jitpack.io") }
6
+ }
7
+ }
8
+
9
+ val newBuildDir: Directory =
10
+ rootProject.layout.buildDirectory
11
+ .dir("../../build")
12
+ .get()
13
+ rootProject.layout.buildDirectory.value(newBuildDir)
14
+
15
+ subprojects {
16
+ val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
17
+ project.layout.buildDirectory.value(newSubprojectBuildDir)
18
+ }
19
+ subprojects {
20
+ project.evaluationDependsOn(":app")
21
+ }
22
+
23
+ tasks.register<Delete>("clean") {
24
+ delete(rootProject.layout.buildDirectory)
25
+ }
android/build/reports/problems/problems-report.html ADDED
The diff for this file is too large to render. See raw diff
 
android/gradle.properties ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
2
+ android.useAndroidX=true
android/gradle/wrapper/gradle-wrapper.properties ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ distributionBase=GRADLE_USER_HOME
2
+ distributionPath=wrapper/dists
3
+ zipStoreBase=GRADLE_USER_HOME
4
+ zipStorePath=wrapper/dists
5
+ distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
android/settings.gradle.kts ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pluginManagement {
2
+ val flutterSdkPath =
3
+ run {
4
+ val properties = java.util.Properties()
5
+ file("local.properties").inputStream().use { properties.load(it) }
6
+ val flutterSdkPath = properties.getProperty("flutter.sdk")
7
+ require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
8
+ flutterSdkPath
9
+ }
10
+
11
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
12
+
13
+ repositories {
14
+ google()
15
+ mavenCentral()
16
+ gradlePluginPortal()
17
+ }
18
+ }
19
+
20
+ plugins {
21
+ id("dev.flutter.flutter-plugin-loader") version "1.0.0"
22
+ id("com.android.application") version "8.11.1" apply false
23
+ id("org.jetbrains.kotlin.android") version "2.2.20" apply false
24
+ }
25
+
26
+ include(":app")
assets/blocklist/india_scam_domains.txt ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # KYC Fraud domains
2
+ hdfcbank-kyc.net
3
+ sbi-kyc-verify.top
4
+ icici-kyc-update.xyz
5
+ axis-kyc-expire.click
6
+ pnb-kyc-alert.com
7
+ bob-kyc-update.in
8
+
9
+ # Fake bank portals
10
+ netbanking-hdfc.com
11
+ sbi-netbanking.xyz
12
+ icici-ibank.top
13
+ hdfc-secure-login.net
14
+ axisbank-online-secure.com
15
+ sbi-reward-points.online
16
+ hdfc-reward-redeem.in
17
+ icici-card-block.xyz
18
+
19
+ # UPI Fraud domains
20
+ upi-reward-claim.xyz
21
+ paytm-cashback-offer.top
22
+ phonepe-winner.click
23
+ gpay-prize.tk
24
+ bhim-upi-cashback.in
25
+ upi-refund-process.top
26
+ phonepe-support-care.com
27
+
28
+ # Lottery / Prize scams
29
+ india-lottery-winner.net
30
+ bsnl-prize-claim.xyz
31
+ jio-recharge-free.top
32
+ airtel-winner-prize.click
33
+ kbc-lottery-winner.in
34
+ tata-safari-winner.club
35
+ mahindra-thar-prize.com
36
+
37
+ # Fake government portals
38
+ pm-kisan-apply.xyz
39
+ aadhar-update-now.top
40
+ pan-verify-online.click
41
+ income-tax-refund.net
42
+ epfo-claim-status.in
43
+ passport-sewa-india.org
44
+ voter-id-verify.online
45
+ cowin-certificate-download.click
46
+
47
+ # Investment scams
48
+ trading-profit-india.xyz
49
+ stock-tip-guaranteed.top
50
+ crypto-india-profit.click
51
+ bitcoin-doubler.in
52
+ nse-bse-tips.club
53
+ zerodha-trading-bonus.online
54
+
55
+ # Loan app harassment
56
+ insta-loan-now.xyz
57
+ quick-cash-app.top
58
+ easy-money-india.click
59
+ dhani-loan-approve.in
60
+ kreditbee-instant.site
61
+ navi-loan-offer.xyz
62
+
63
+ # Extortion / Threats
64
+ cyber-crime-notice.in
65
+ cbi-investigation-portal.org
66
+ rbi-penalty-payment.com
67
+ customs-clearance-fee.xyz
68
+ trai-number-block.top
assets/seed_embeddings.json ADDED
The diff for this file is too large to render. See raw diff
 
build_err.txt ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Running Gradle task 'assembleDebug'...
2
+
3
+ FAILURE: Build failed with an exception.
4
+
5
+ * What went wrong:
6
+ Execution failed for task ':llama_sdk:configureCMakeDebug[arm64-v8a]'.
7
+ > [CXX1429] error when building with cmake using /Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android/CMakeLists.txt: -- The C compiler identification is Clang 18.0.1
8
+ -- The CXX compiler identification is Clang 18.0.1
9
+ -- Detecting C compiler ABI info
10
+ -- Detecting C compiler ABI info - done
11
+ -- Check for working C compiler: /Users/friday/Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang - skipped
12
+ -- Detecting C compile features
13
+ -- Detecting C compile features - done
14
+ -- Detecting CXX compiler ABI info
15
+ -- Detecting CXX compiler ABI info - done
16
+ -- Check for working CXX compiler: /Users/friday/Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ - skipped
17
+ -- Detecting CXX compile features
18
+ -- Detecting CXX compile features - done
19
+ -- Configuring incomplete, errors occurred!
20
+ See also "/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android/.cxx/Debug/1y5h19dr/arm64-v8a/CMakeFiles/CMakeOutput.log".
21
+
22
+ C++ build system [configure] failed while executing:
23
+ /Users/friday/Library/Android/sdk/cmake/3.22.1/bin/cmake \
24
+ -H/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android \
25
+ -DCMAKE_SYSTEM_NAME=Android \
26
+ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
27
+ -DCMAKE_SYSTEM_VERSION=23 \
28
+ -DANDROID_PLATFORM=android-23 \
29
+ -DANDROID_ABI=arm64-v8a \
30
+ -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
31
+ -DANDROID_NDK=/Users/friday/Library/Android/sdk/ndk/27.0.12077973 \
32
+ -DCMAKE_ANDROID_NDK=/Users/friday/Library/Android/sdk/ndk/27.0.12077973 \
33
+ -DCMAKE_TOOLCHAIN_FILE=/Users/friday/Library/Android/sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake \
34
+ -DCMAKE_MAKE_PROGRAM=/Users/friday/Library/Android/sdk/cmake/3.22.1/bin/ninja \
35
+ -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/Users/friday/premithus/build/llama_sdk/intermediates/cxx/Debug/1y5h19dr/obj/arm64-v8a \
36
+ -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/Users/friday/premithus/build/llama_sdk/intermediates/cxx/Debug/1y5h19dr/obj/arm64-v8a \
37
+ -DCMAKE_BUILD_TYPE=Debug \
38
+ -B/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android/.cxx/Debug/1y5h19dr/arm64-v8a \
39
+ -GNinja
40
+ from /Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android
41
+ CMake Error at CMakeLists.txt:15 (add_subdirectory):
42
+ The source directory
43
+
44
+ /Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/src/llama_cpp
45
+
46
+ does not contain a CMakeLists.txt file.
47
+
48
+
49
+ CMake Error at CMakeLists.txt:17 (target_include_directories):
50
+ Cannot specify include directories for target "llama" which is not built by
51
+ this project.
52
+
53
+
54
+ CMake Error at CMakeLists.txt:23 (target_sources):
55
+ Cannot specify sources for target "llama" which is not built by this
56
+ project.
57
+
58
+
59
+ CMake Error at CMakeLists.txt:30 (target_compile_options):
60
+ Cannot specify compile options for target "llama" which is not built by
61
+ this project.
62
+
63
+
64
+ CMake Error at CMakeLists.txt:39 (target_link_options):
65
+ Cannot specify link options for target "llama" which is not built by this
66
+ project.
67
+
68
+
69
+ CMake Error at CMakeLists.txt:49 (target_compile_options):
70
+ Cannot specify compile options for target "llama" which is not built by
71
+ this project. : com.android.ide.common.process.ProcessException: -- The C compiler identification is Clang 18.0.1
72
+ -- The CXX compiler identification is Clang 18.0.1
73
+ -- Detecting C compiler ABI info
74
+ -- Detecting C compiler ABI info - done
75
+ -- Check for working C compiler: /Users/friday/Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang - skipped
76
+ -- Detecting C compile features
77
+ -- Detecting C compile features - done
78
+ -- Detecting CXX compiler ABI info
79
+ -- Detecting CXX compiler ABI info - done
80
+ -- Check for working CXX compiler: /Users/friday/Library/Android/sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ - skipped
81
+ -- Detecting CXX compile features
82
+ -- Detecting CXX compile features - done
83
+ -- Configuring incomplete, errors occurred!
84
+ See also "/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android/.cxx/Debug/1y5h19dr/arm64-v8a/CMakeFiles/CMakeOutput.log".
85
+
86
+ C++ build system [configure] failed while executing:
87
+ /Users/friday/Library/Android/sdk/cmake/3.22.1/bin/cmake \
88
+ -H/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android \
89
+ -DCMAKE_SYSTEM_NAME=Android \
90
+ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
91
+ -DCMAKE_SYSTEM_VERSION=23 \
92
+ -DANDROID_PLATFORM=android-23 \
93
+ -DANDROID_ABI=arm64-v8a \
94
+ -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
95
+ -DANDROID_NDK=/Users/friday/Library/Android/sdk/ndk/27.0.12077973 \
96
+ -DCMAKE_ANDROID_NDK=/Users/friday/Library/Android/sdk/ndk/27.0.12077973 \
97
+ -DCMAKE_TOOLCHAIN_FILE=/Users/friday/Library/Android/sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake \
98
+ -DCMAKE_MAKE_PROGRAM=/Users/friday/Library/Android/sdk/cmake/3.22.1/bin/ninja \
99
+ -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/Users/friday/premithus/build/llama_sdk/intermediates/cxx/Debug/1y5h19dr/obj/arm64-v8a \
100
+ -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/Users/friday/premithus/build/llama_sdk/intermediates/cxx/Debug/1y5h19dr/obj/arm64-v8a \
101
+ -DCMAKE_BUILD_TYPE=Debug \
102
+ -B/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android/.cxx/Debug/1y5h19dr/arm64-v8a \
103
+ -GNinja
104
+ from /Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android
105
+ CMake Error at CMakeLists.txt:15 (add_subdirectory):
106
+ The source directory
107
+
108
+ /Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/src/llama_cpp
109
+
110
+ does not contain a CMakeLists.txt file.
111
+
112
+
113
+ CMake Error at CMakeLists.txt:17 (target_include_directories):
114
+ Cannot specify include directories for target "llama" which is not built by
115
+ this project.
116
+
117
+
118
+ CMake Error at CMakeLists.txt:23 (target_sources):
119
+ Cannot specify sources for target "llama" which is not built by this
120
+ project.
121
+
122
+
123
+ CMake Error at CMakeLists.txt:30 (target_compile_options):
124
+ Cannot specify compile options for target "llama" which is not built by
125
+ this project.
126
+
127
+
128
+ CMake Error at CMakeLists.txt:39 (target_link_options):
129
+ Cannot specify link options for target "llama" which is not built by this
130
+ project.
131
+
132
+
133
+ CMake Error at CMakeLists.txt:49 (target_compile_options):
134
+ Cannot specify compile options for target "llama" which is not built by
135
+ this project.
136
+ at com.android.build.gradle.internal.cxx.process.ExecuteProcessKt.execute(ExecuteProcess.kt:288)
137
+ at com.android.build.gradle.internal.cxx.process.ExecuteProcessKt$executeProcess$1.invoke(ExecuteProcess.kt:108)
138
+ at com.android.build.gradle.internal.cxx.process.ExecuteProcessKt$executeProcess$1.invoke(ExecuteProcess.kt:106)
139
+ at com.android.build.gradle.internal.cxx.timing.TimingEnvironmentKt.time(TimingEnvironment.kt:32)
140
+ at com.android.build.gradle.internal.cxx.process.ExecuteProcessKt.executeProcess(ExecuteProcess.kt:106)
141
+ at com.android.build.gradle.internal.cxx.process.ExecuteProcessKt.executeProcess$default(ExecuteProcess.kt:85)
142
+ at com.android.build.gradle.tasks.CmakeQueryMetadataGenerator.executeProcess(CmakeFileApiMetadataGenerator.kt:59)
143
+ at com.android.build.gradle.tasks.ExternalNativeJsonGenerator$configureOneAbi$1$1$3.invoke(ExternalNativeJsonGenerator.kt:247)
144
+ at com.android.build.gradle.tasks.ExternalNativeJsonGenerator$configureOneAbi$1$1$3.invoke(ExternalNativeJsonGenerator.kt:247)
145
+ at com.android.build.gradle.internal.cxx.timing.TimingEnvironmentKt.time(TimingEnvironment.kt:32)
146
+ at com.android.build.gradle.tasks.ExternalNativeJsonGenerator.configureOneAbi(ExternalNativeJsonGenerator.kt:247)
147
+ at com.android.build.gradle.tasks.ExternalNativeJsonGenerator.configure(ExternalNativeJsonGenerator.kt:113)
148
+ at com.android.build.gradle.tasks.ExternalNativeBuildJsonTask.doTaskAction(ExternalNativeBuildJsonTask.kt:89)
149
+ at com.android.build.gradle.internal.tasks.UnsafeOutputsTask$taskAction$$inlined$recordTaskAction$1.invoke(BaseTask.kt:59)
150
+ at com.android.build.gradle.internal.tasks.Blocks.recordSpan(Blocks.java:51)
151
+ at com.android.build.gradle.internal.tasks.UnsafeOutputsTask.taskAction(UnsafeOutputsTask.kt:81)
152
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
153
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
154
+ at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125)
155
+ at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
156
+ at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
157
+ at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
158
+ at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:244)
159
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30)
160
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27)
161
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67)
162
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60)
163
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167)
164
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60)
165
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48)
166
+ at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:229)
167
+ at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:212)
168
+ at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:195)
169
+ at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:162)
170
+ at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:105)
171
+ at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:44)
172
+ at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:59)
173
+ at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:56)
174
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210)
175
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205)
176
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67)
177
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60)
178
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167)
179
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60)
180
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54)
181
+ at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:56)
182
+ at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:44)
183
+ at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:42)
184
+ at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:75)
185
+ at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
186
+ at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:50)
187
+ at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:28)
188
+ at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:67)
189
+ at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:37)
190
+ at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:61)
191
+ at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:26)
192
+ at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:69)
193
+ at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:46)
194
+ at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:40)
195
+ at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:29)
196
+ at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:189)
197
+ at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
198
+ at org.gradle.internal.Either$Right.fold(Either.java:175)
199
+ at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:62)
200
+ at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
201
+ at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
202
+ at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:46)
203
+ at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:35)
204
+ at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:75)
205
+ at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:53)
206
+ at java.base/java.util.Optional.orElseGet(Unknown Source)
207
+ at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:53)
208
+ at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:35)
209
+ at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
210
+ at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
211
+ at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:49)
212
+ at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:27)
213
+ at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:71)
214
+ at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:39)
215
+ at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:65)
216
+ at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:36)
217
+ at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:107)
218
+ at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:56)
219
+ at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:64)
220
+ at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:43)
221
+ at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.executeWithNonEmptySources(AbstractSkipEmptyWorkStep.java:125)
222
+ at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:56)
223
+ at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:36)
224
+ at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
225
+ at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:36)
226
+ at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:23)
227
+ at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:75)
228
+ at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:41)
229
+ at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.lambda$execute$0(AssignMutableWorkspaceStep.java:35)
230
+ at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:289)
231
+ at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:31)
232
+ at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:22)
233
+ at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:40)
234
+ at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23)
235
+ at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67)
236
+ at java.base/java.util.Optional.orElseGet(Unknown Source)
237
+ at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67)
238
+ at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39)
239
+ at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46)
240
+ at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34)
241
+ at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:48)
242
+ at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:35)
243
+ at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:64)
244
+ at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:127)
245
+ at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:116)
246
+ at org.gradle.api.internal.tasks.execution.ProblemsTaskPathTrackingTaskExecuter.execute(ProblemsTaskPathTrackingTaskExecuter.java:41)
247
+ at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
248
+ at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
249
+ at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
250
+ at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74)
251
+ at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
252
+ at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
253
+ at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
254
+ at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
255
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210)
256
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205)
257
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67)
258
+ at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60)
259
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167)
260
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60)
261
+ at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54)
262
+ at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
263
+ at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:42)
264
+ at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:331)
265
+ at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:318)
266
+ at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:314)
267
+ at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:85)
268
+ at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:314)
269
+ at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:303)
270
+ at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:459)
271
+ at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:376)
272
+ at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
273
+ at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48)
274
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
275
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
276
+ at java.base/java.lang.Thread.run(Unknown Source)
277
+ Caused by: com.android.ide.common.process.ProcessException: Error while executing process /Users/friday/Library/Android/sdk/cmake/3.22.1/bin/cmake with arguments {-H/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android -DCMAKE_SYSTEM_NAME=Android -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_SYSTEM_VERSION=23 -DANDROID_PLATFORM=android-23 -DANDROID_ABI=arm64-v8a -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DANDROID_NDK=/Users/friday/Library/Android/sdk/ndk/27.0.12077973 -DCMAKE_ANDROID_NDK=/Users/friday/Library/Android/sdk/ndk/27.0.12077973 -DCMAKE_TOOLCHAIN_FILE=/Users/friday/Library/Android/sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake -DCMAKE_MAKE_PROGRAM=/Users/friday/Library/Android/sdk/cmake/3.22.1/bin/ninja -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/Users/friday/premithus/build/llama_sdk/intermediates/cxx/Debug/1y5h19dr/obj/arm64-v8a -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/Users/friday/premithus/build/llama_sdk/intermediates/cxx/Debug/1y5h19dr/obj/arm64-v8a -DCMAKE_BUILD_TYPE=Debug -B/Users/friday/.pub-cache/git/lcpp-7c2f8423e87781859acc514cd0aa36554f423163/android/.cxx/Debug/1y5h19dr/arm64-v8a -GNinja}
278
+ at com.android.build.gradle.internal.process.GradleProcessResult.buildProcessException(GradleProcessResult.java:73)
279
+ at com.android.build.gradle.internal.process.GradleProcessResult.assertNormalExitValue(GradleProcessResult.java:48)
280
+ at com.android.build.gradle.internal.cxx.process.ExecuteProcessKt.execute(ExecuteProcess.kt:277)
281
+ ... 140 more
282
+ Caused by: org.gradle.process.internal.ExecException: Process 'command '/Users/friday/Library/Android/sdk/cmake/3.22.1/bin/cmake'' finished with non-zero exit value 1
283
+ at org.gradle.process.internal.DefaultExecHandle$ExecResultImpl.assertNormalExitValue(DefaultExecHandle.java:442)
284
+ at com.android.build.gradle.internal.process.GradleProcessResult.assertNormalExitValue(GradleProcessResult.java:46)
285
+ ... 141 more
286
+
287
+
288
+ * Try:
289
+ > Run with --stacktrace option to get the stack trace.
290
+ > Run with --info or --debug option to get more log output.
291
+ > Run with --scan to get full insights.
292
+ > Get more help at https://help.gradle.org.
293
+
294
+ BUILD FAILED in 2s
295
+ Running Gradle task 'assembleDebug'... 2,115ms
296
+ Gradle task assembleDebug failed with exit code 1
convert_bert.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow as tf
2
+ from transformers import AutoTokenizer, TFAutoModelForSequenceClassification
3
+ import os
4
+
5
+ model_name = "mrm8488/bert-tiny-finetuned-sms-spam-detection"
6
+
7
+ print("Loading model and tokenizer...")
8
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
9
+ model = TFAutoModelForSequenceClassification.from_pretrained(model_name, from_pt=True)
10
+
11
+ print("Exporting vocab...")
12
+ os.makedirs("models", exist_ok=True)
13
+ with open("models/vocab.txt", "w", encoding="utf-8") as f:
14
+ for token, index in sorted(tokenizer.get_vocab().items(), key=lambda x: x[1]):
15
+ f.write(f"{token}\n")
16
+
17
+ print("Tracing model for TFLite conversion...")
18
+ MAX_SEQ_LEN = 128
19
+
20
+ callable_model = tf.function(
21
+ lambda input_ids, attention_mask: model(input_ids=input_ids, attention_mask=attention_mask, training=False)
22
+ )
23
+
24
+ concrete_func = callable_model.get_concrete_function(
25
+ tf.TensorSpec([1, MAX_SEQ_LEN], tf.int32, name="input_ids"),
26
+ tf.TensorSpec([1, MAX_SEQ_LEN], tf.int32, name="attention_mask")
27
+ )
28
+
29
+ print("Converting to TFLite...")
30
+ converter = tf.lite.TFLiteConverter.from_concrete_functions([concrete_func])
31
+ converter.optimizations = [tf.lite.Optimize.DEFAULT]
32
+ converter.target_spec.supported_ops = [
33
+ tf.lite.OpsSet.TFLITE_BUILTINS,
34
+ tf.lite.OpsSet.SELECT_TF_OPS
35
+ ]
36
+
37
+ tflite_model = converter.convert()
38
+
39
+ with open("models/scam_classifier.tflite", "wb") as f:
40
+ f.write(tflite_model)
41
+
42
+ print("Done! Model saved to models/scam_classifier.tflite")
demo_script_v0.0.2.md ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Premithius V0.0.2 Demo Script
2
+
3
+ **Theme:** India-First On-Device AI Security | Zero LLM | ARMadillo Architecture
4
+
5
+ ## Demo 1: The Zero-Day Scam (Vector Engine)
6
+ **Scenario:** A completely new scam variant that isn't in any blacklist yet.
7
+ 1. Send SMS to emulator: `adb shell am broadcast -a android.provider.Telephony.SMS_RECEIVED -d "SMS_BODY:Urgent! Your HDFC acct is blocked. Update KYC immediately via http://hdfc.kyc-update-xyz.in"`
8
+ 2. **Observe:** Premithius overlay appears instantly (under 50ms).
9
+ 3. **Explanation:** "Unlike cloud antiviruses that need updates, our `sqlite-vec` engine running locally instantly recognized the semantic meaning of 'urgent KYC update' bypassing traditional filters. It never left the device."
10
+
11
+ ## Demo 2: The UPI Rs. 1 Collect Fraud (India Threat Pack)
12
+ **Scenario:** The classic OLX/Marketplace fraud.
13
+ 1. Send SMS: `adb shell am broadcast -a android.provider.Telephony.SMS_RECEIVED -d "SMS_BODY:Dear Customer, Rs 12,500 has been credited... To receive money, please authorize Rs. 1 collect request from VPA: scammer@ybl"`
14
+ 2. **Observe:** Kavacha Firewall blocks it natively.
15
+ 3. **Explanation:** "Our Layer 1 India Threat Pack specifically targets regional payment infrastructure. We catch the ₹1 collect trick natively before it hits complex models."
16
+
17
+ ## Demo 3: Data Shield & System Visibility
18
+ 1. Open the Premithius App -> Navigate to **Data Shield Insights**
19
+ 2. **Observe:** Plain English translations of complex OS data (e.g., "TikTok sent 340 MB of data between 2am–4am last night").
20
+ 3. **Explanation:** "Instead of obscure permission screens, we translate system telemetry into human-readable privacy stories. The home screen widget surfaces these anomalies effortlessly."
21
+
22
+ ## Demo 4: Aadhaar/PAN Outgoing Intercept (Keyboard)
23
+ **Scenario:** User typing their Aadhaar number to a stranger on WhatsApp.
24
+ 1. Open any chat app.
25
+ 2. Select Premithius Keyboard.
26
+ 3. Type: `Mera Aadhaar 1234 5678 9012 hai` and hit Enter/Send.
27
+ 4. **Observe:** Warning overlay/snack bar: "Wait! You are about to send a sensitive ID."
28
+ 5. **Explanation:** "Our keyboard is the final line of defense. It detects outbound PII like Aadhaar or PAN on the edge, warning the user *before* it ends up on a scammer's server."
hf_space ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit ca0c577efb6417cf89c554b17f3c9b8af9a3fa42
index.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width" />
6
+ <title>My static Space</title>
7
+ <link rel="stylesheet" href="style.css" />
8
+ </head>
9
+ <body>
10
+ <div class="card">
11
+ <h1>Welcome to your static Space!</h1>
12
+ <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
+ <p>
14
+ Also don't forget to check the
15
+ <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
+ </p>
17
+ </div>
18
+ </body>
19
+ </html>
ios/.gitignore ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ **/dgph
2
+ *.mode1v3
3
+ *.mode2v3
4
+ *.moved-aside
5
+ *.pbxuser
6
+ *.perspectivev3
7
+ **/*sync/
8
+ .sconsign.dblite
9
+ .tags*
10
+ **/.vagrant/
11
+ **/DerivedData/
12
+ Icon?
13
+ **/Pods/
14
+ **/.symlinks/
15
+ profile
16
+ xcuserdata
17
+ **/.generated/
18
+ Flutter/App.framework
19
+ Flutter/Flutter.framework
20
+ Flutter/Flutter.podspec
21
+ Flutter/Generated.xcconfig
22
+ Flutter/ephemeral/
23
+ Flutter/app.flx
24
+ Flutter/app.zip
25
+ Flutter/flutter_assets/
26
+ Flutter/flutter_export_environment.sh
27
+ ServiceDefinitions.json
28
+ Runner/GeneratedPluginRegistrant.*
29
+
30
+ # Exceptions to above rules.
31
+ !default.mode1v3
32
+ !default.mode2v3
33
+ !default.pbxuser
34
+ !default.perspectivev3
ios/Flutter/AppFrameworkInfo.plist ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>en</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>App</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>io.flutter.flutter.app</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>App</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleSignature</key>
20
+ <string>????</string>
21
+ <key>CFBundleVersion</key>
22
+ <string>1.0</string>
23
+ </dict>
24
+ </plist>
ios/Flutter/Debug.xcconfig ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2
+ #include "Generated.xcconfig"