android-ai-skills 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +250 -0
  3. package/android-auth-identity/SKILL.md +36 -0
  4. package/android-auth-identity/references/biometric_auth.md +36 -0
  5. package/android-auth-identity/references/credential_manager.md +32 -0
  6. package/android-auth-identity/references/google_sign_in.md +39 -0
  7. package/android-auth-identity/references/session_security.md +33 -0
  8. package/android-auth-identity/references/token_management.md +33 -0
  9. package/android-ci-cd/SKILL.md +36 -0
  10. package/android-ci-cd/references/build_optimization.md +39 -0
  11. package/android-ci-cd/references/fastlane.md +34 -0
  12. package/android-ci-cd/references/github_actions.md +35 -0
  13. package/android-ci-cd/references/play_store_deployment.md +36 -0
  14. package/android-ci-cd/references/signing_ci.md +39 -0
  15. package/android-dependency-injection/SKILL.md +36 -0
  16. package/android-dependency-injection/references/common_mistakes.md +37 -0
  17. package/android-dependency-injection/references/hilt_setup.md +32 -0
  18. package/android-dependency-injection/references/multi_module_di.md +31 -0
  19. package/android-dependency-injection/references/scoping.md +34 -0
  20. package/android-dependency-injection/references/testing_di.md +36 -0
  21. package/android-local-storage/SKILL.md +36 -0
  22. package/android-local-storage/references/cache_strategies.md +33 -0
  23. package/android-local-storage/references/datastore.md +35 -0
  24. package/android-local-storage/references/encryption.md +35 -0
  25. package/android-local-storage/references/offline_first.md +39 -0
  26. package/android-local-storage/references/room_patterns.md +34 -0
  27. package/android-maps-location/SKILL.md +35 -0
  28. package/android-maps-location/references/fused_location.md +40 -0
  29. package/android-maps-location/references/geofencing.md +36 -0
  30. package/android-maps-location/references/google_maps.md +39 -0
  31. package/android-maps-location/references/location_permissions.md +34 -0
  32. package/android-media/SKILL.md +36 -0
  33. package/android-media/references/audio_focus.md +34 -0
  34. package/android-media/references/camerax.md +40 -0
  35. package/android-media/references/image_loading.md +37 -0
  36. package/android-media/references/media3_playback.md +40 -0
  37. package/android-media/references/picture_in_picture.md +34 -0
  38. package/android-ml-ondevice/SKILL.md +35 -0
  39. package/android-ml-ondevice/references/gemini_nano.md +36 -0
  40. package/android-ml-ondevice/references/ml_kit.md +34 -0
  41. package/android-ml-ondevice/references/model_management.md +41 -0
  42. package/android-ml-ondevice/references/tensorflow_lite.md +42 -0
  43. package/android-networking/SKILL.md +36 -0
  44. package/android-networking/references/caching.md +31 -0
  45. package/android-networking/references/error_handling.md +32 -0
  46. package/android-networking/references/ktor_multiplatform.md +33 -0
  47. package/android-networking/references/okhttp_interceptors.md +34 -0
  48. package/android-networking/references/retrofit_setup.md +33 -0
  49. package/bin/android-ai-skills.js +30 -0
  50. package/firebase-best-practices/SKILL.md +37 -0
  51. package/firebase-best-practices/references/analytics.md +36 -0
  52. package/firebase-best-practices/references/cloud_messaging.md +34 -0
  53. package/firebase-best-practices/references/crashlytics.md +35 -0
  54. package/firebase-best-practices/references/firebase_auth.md +34 -0
  55. package/firebase-best-practices/references/firestore.md +36 -0
  56. package/firebase-best-practices/references/remote_config.md +34 -0
  57. package/package.json +11 -1
  58. package/play-billing-best-practices/SKILL.md +36 -0
  59. package/play-billing-best-practices/references/billing_client_lifecycle.md +28 -0
  60. package/play-billing-best-practices/references/one_time_purchases.md +29 -0
  61. package/play-billing-best-practices/references/server_verification.md +34 -0
  62. package/play-billing-best-practices/references/subscriptions.md +29 -0
  63. package/play-billing-best-practices/references/testing_billing.md +34 -0
@@ -0,0 +1,36 @@
1
+ # Play Store Deployment
2
+
3
+ ## Gradle Play Publisher
4
+ - Plugin: com.github.triplet.play — automates Play Store uploads.
5
+ - Configure: play { track.set("internal"); defaultToAppBundles.set(true) }.
6
+ - Tasks: publishBundle (upload AAB), publishListing (update metadata), promoteArtifact (promote track).
7
+ - Authenticate with service account JSON key from Google Cloud.
8
+ - Store service account key as CI secret — never commit.
9
+
10
+ ## Service Account Setup
11
+ - Create service account in Google Cloud Console.
12
+ - Grant "Service Account User" role.
13
+ - In Play Console: invite service account email with "Release manager" permissions.
14
+ - Download JSON key — store as CI secret.
15
+ - Key has no expiry — rotate periodically for security.
16
+
17
+ ## Deployment Strategy
18
+ - Internal track: every merge to main — continuous delivery.
19
+ - Closed testing: weekly or on-demand for QA team.
20
+ - Production: manual trigger or tag-based release.
21
+ - Staged rollout: start at 5-10%, monitor, expand to 100%.
22
+ - Use GitHub Releases or tags to trigger production deployment.
23
+
24
+ ## Metadata Management
25
+ - Store release notes in fastlane/metadata/android/ or play/ directory.
26
+ - Per-locale directories: en-US/, es-ES/, etc.
27
+ - Files: title.txt, short_description.txt, full_description.txt, changelogs/*.txt.
28
+ - Automate metadata upload with publishListing task.
29
+ - Version changelog in changelogs/{versionCode}.txt.
30
+
31
+ ## Rollback
32
+ - Play Console: halt rollout to stop distribution of current version.
33
+ - Re-promote previous version to resume old version distribution.
34
+ - Alternatively: upload a hotfix with incremented versionCode.
35
+ - Monitor Android Vitals during rollout — halt on crash rate regression.
36
+ - Have a documented rollback procedure before every release.
@@ -0,0 +1,39 @@
1
+ # Signing in CI
2
+
3
+ ## Keystore Management
4
+ - Never commit keystore files to the repository.
5
+ - Encode keystore as base64: base64 -i release.keystore | pbcopy.
6
+ - Store base64 string as CI secret: KEYSTORE_BASE64.
7
+ - Decode in CI: echo $KEYSTORE_BASE64 | base64 --decode > release.keystore.
8
+ - Delete keystore after build completes — don't leave on CI runner.
9
+
10
+ ## Secret Configuration
11
+ - Required secrets: KEYSTORE_BASE64, KEYSTORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD.
12
+ - Reference in build.gradle.kts via System.getenv().
13
+ - signingConfigs.release { storeFile = file(keystorePath); storePassword = System.getenv("KEYSTORE_PASSWORD") }.
14
+ - Never hardcode fallback values — fail the build if secrets are missing.
15
+
16
+ ## GitHub Actions Example
17
+ ```yaml
18
+ - name: Decode keystore
19
+ run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > app/release.keystore
20
+ - name: Build release
21
+ env:
22
+ KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
23
+ KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
24
+ KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
25
+ run: ./gradlew bundleRelease
26
+ ```
27
+
28
+ ## Play App Signing
29
+ - Upload key (your key) signs the AAB before uploading.
30
+ - Google re-signs with the app signing key for distribution.
31
+ - If upload key is compromised: request reset in Play Console.
32
+ - Upload key can be different from the app signing key.
33
+
34
+ ## Best Practices
35
+ - Use separate upload key from app signing key.
36
+ - Rotate upload key periodically (Play Console allows reset).
37
+ - Audit CI secrets access — limit to deployment workflows only.
38
+ - Use environment-specific signing: debug (auto), staging (shared), release (CI secret).
39
+ - Test signed builds locally before relying on CI: ./gradlew bundleRelease.
@@ -0,0 +1,36 @@
1
+
2
+ ---
3
+ name: android-dependency-injection
4
+ description: Dependency injection with Hilt/Dagger — setup, scoping, multi-module, testing.
5
+ ---
6
+
7
+ # Android Dependency Injection
8
+
9
+ Cross-cutting skill — always activates alongside the project-type-specific skill.
10
+
11
+ ## Hard Rules
12
+ - Use Hilt as the default DI framework for Android projects.
13
+ - Annotate Application class with @HiltAndroidApp.
14
+ - Annotate all Activities and Fragments that use injection with @AndroidEntryPoint.
15
+ - Scope dependencies correctly — @Singleton for app-wide, @ViewModelScoped for ViewModel lifetime.
16
+ - Never inject Activity or Fragment context into @Singleton-scoped objects — use @ApplicationContext.
17
+ - Define bindings in @Module classes — use @Binds for interface-to-implementation, @Provides for construction.
18
+ - Use @Qualifier annotations to distinguish same-type bindings — not named strings.
19
+ - Keep modules focused — one module per feature boundary.
20
+ - Use constructor injection over field injection wherever possible.
21
+ - Never use Dagger directly when Hilt is available — Hilt reduces boilerplate.
22
+
23
+ ## Core Patterns
24
+ - @InstallIn(SingletonComponent::class) for app-wide singletons.
25
+ - @InstallIn(ViewModelComponent::class) for ViewModel-scoped dependencies.
26
+ - Use @AssistedInject for WorkManager Workers and other assisted construction.
27
+ - Define interface in feature-api, implementation binding in feature-impl module.
28
+ - Use @EntryPoint for injecting into classes Hilt doesn't manage (ContentProvider, etc.).
29
+ - Wrap third-party SDK initialization in @Provides methods for testability.
30
+
31
+ ## References
32
+ - references/hilt_setup.md
33
+ - references/scoping.md
34
+ - references/multi_module_di.md
35
+ - references/testing_di.md
36
+ - references/common_mistakes.md
@@ -0,0 +1,37 @@
1
+ # Common DI Mistakes
2
+
3
+ ## Scoping Leaks
4
+ - Injecting Activity context into @Singleton scope — Activity leaks.
5
+ - Fix: use @ApplicationContext for singleton-scoped dependencies.
6
+ - Injecting ViewModel into @Singleton — ViewModel outlives its scope.
7
+ - Fix: use @ViewModelScoped or don't scope the consuming class.
8
+
9
+ ## Missing Entry Points
10
+ - Forgetting @AndroidEntryPoint on Activity that hosts injected Fragments.
11
+ - Forgetting @HiltAndroidApp on Application class.
12
+ - Forgetting to add hilt-android-compiler to KSP configuration.
13
+ - Error: "Hilt Activity must be attached to an @AndroidEntryPoint Application."
14
+
15
+ ## Circular Dependencies
16
+ - A depends on B, B depends on A — Dagger/Hilt fails at compile time.
17
+ - Fix: introduce an interface to break the cycle.
18
+ - Fix: use Provider<T> or Lazy<T> for deferred resolution.
19
+ - Review dependency graph if cycles emerge — usually indicates design issue.
20
+
21
+ ## Field Injection Pitfalls
22
+ - @Inject lateinit var in Fragments — must call inject before accessing.
23
+ - Field injection not available in data classes or objects.
24
+ - Prefer constructor injection — field injection hides dependencies.
25
+ - Only use field injection where constructor injection is impossible (Activities, Fragments).
26
+
27
+ ## Module Mistakes
28
+ - @Provides without @Module — binding is silently ignored.
29
+ - @Module without @InstallIn — compile error (Hilt requires component).
30
+ - @Binds with implementation class — must be abstract function in abstract module.
31
+ - @Provides returning interface type but Hilt can't find the implementation.
32
+
33
+ ## Multi-Module Issues
34
+ - Missing feature-impl dependency in :app module — binding not found at compile time.
35
+ - Duplicate bindings across modules — use @Qualifier to disambiguate.
36
+ - Installing test module in wrong component — bindings not visible to the test.
37
+ - Feature module with @InstallIn(ActivityComponent::class) — consider if SingletonComponent is more appropriate.
@@ -0,0 +1,32 @@
1
+ # Hilt Setup
2
+
3
+ ## Gradle Configuration
4
+ - Add hilt-android and hilt-android-compiler (KSP) dependencies.
5
+ - Apply com.google.dagger.hilt.android plugin.
6
+ - Use KSP (not KAPT) for faster annotation processing.
7
+ - Add hilt-navigation-compose for ViewModel injection in Navigation Compose.
8
+
9
+ ## Application
10
+ - Annotate Application class with @HiltAndroidApp.
11
+ - This generates the Hilt component hierarchy rooted at SingletonComponent.
12
+ - Application class is required — Hilt cannot work without it.
13
+
14
+ ## Android Entry Points
15
+ - @AndroidEntryPoint on Activities that use injection.
16
+ - @AndroidEntryPoint on Fragments that use injection.
17
+ - Activities must be @AndroidEntryPoint if their Fragments use injection.
18
+ - Services, BroadcastReceivers, and Views can also be @AndroidEntryPoint.
19
+
20
+ ## Modules
21
+ - @Module + @InstallIn(Component::class) for providing dependencies.
22
+ - @Provides for creating instances with constructor logic.
23
+ - @Binds for mapping interface to implementation (more efficient than @Provides).
24
+ - companion object with @Provides for static factory methods.
25
+ - Separate modules by concern: NetworkModule, DatabaseModule, RepositoryModule.
26
+
27
+ ## ViewModel
28
+ - Annotate ViewModel with @HiltViewModel.
29
+ - Use @Inject constructor for ViewModel dependencies.
30
+ - Access in Compose: hiltViewModel() from hilt-navigation-compose.
31
+ - Access in Fragment: by viewModels().
32
+ - SavedStateHandle is automatically available in @HiltViewModel constructor.
@@ -0,0 +1,31 @@
1
+ # Multi-Module DI
2
+
3
+ ## Pattern
4
+ - feature-api module: defines interfaces (Repository, UseCase contracts).
5
+ - feature-impl module: implements interfaces, provides Hilt bindings.
6
+ - :app module: depends on all feature-impl modules, wires everything together.
7
+ - Core modules: provide shared utilities (networking, database).
8
+
9
+ ## Binding in Feature Modules
10
+ - Define @Module in feature-impl with @Binds mapping interface → implementation.
11
+ - @InstallIn(SingletonComponent::class) for cross-feature shared instances.
12
+ - @InstallIn(ViewModelComponent::class) for per-ViewModel instances.
13
+ - Feature-impl module has implementation dependency on feature-api.
14
+
15
+ ## Cross-Feature Dependencies
16
+ - Feature A needs Feature B's repository: depend on feature-b-api (interface only).
17
+ - Hilt resolves the binding from feature-b-impl at compile time in :app.
18
+ - Features never depend on other feature-impl modules directly.
19
+ - This maintains loose coupling and parallel build.
20
+
21
+ ## Navigation DI
22
+ - Feature-api exposes route classes — no DI needed for navigation contracts.
23
+ - ViewModels in feature-impl use @HiltViewModel with injected dependencies.
24
+ - Use hiltViewModel() in composable destinations for automatic scoping.
25
+ - Shared data: pass via navigation arguments, not shared ViewModel instances.
26
+
27
+ ## Aggregation
28
+ - :app module aggregates all @InstallIn modules automatically.
29
+ - Hilt scans all transitive dependencies for @Module classes.
30
+ - No manual component builder needed — Hilt handles aggregation.
31
+ - Use @EntryPoint when injecting into non-Hilt-managed classes in feature modules.
@@ -0,0 +1,34 @@
1
+ # Scoping
2
+
3
+ ## Component Hierarchy
4
+ - SingletonComponent: application lifetime — @Singleton scope.
5
+ - ActivityRetainedComponent: survives configuration changes — @ActivityRetainedScoped.
6
+ - ViewModelComponent: ViewModel lifetime — @ViewModelScoped.
7
+ - ActivityComponent: Activity lifetime — @ActivityScoped.
8
+ - FragmentComponent: Fragment lifetime — @FragmentScoped.
9
+ - ServiceComponent: Service lifetime — @ServiceScoped.
10
+
11
+ ## Choosing Scope
12
+ - @Singleton: app-wide singletons (Retrofit, OkHttpClient, Database, DataStore).
13
+ - @ViewModelScoped: shared within a ViewModel's dependency graph.
14
+ - Unscoped (no annotation): new instance every time — default and preferred for stateless objects.
15
+ - Prefer unscoped — only add scope when sharing or lifecycle binding is needed.
16
+
17
+ ## Rules
18
+ - Scoped bindings must be installed in a component that matches the scope.
19
+ - @Singleton bindings must be in @InstallIn(SingletonComponent::class).
20
+ - A scoped binding cannot depend on a narrower-scoped binding.
21
+ - Unscoped bindings can be installed in any component.
22
+ - Wider scope = longer lifetime = more memory usage — scope conservatively.
23
+
24
+ ## Common Mistakes
25
+ - Over-scoping: making everything @Singleton wastes memory and hides lifecycle issues.
26
+ - Under-scoping: creating expensive objects (database, HTTP client) repeatedly.
27
+ - Injecting Activity/Fragment context into @Singleton — causes memory leaks.
28
+ - Use @ApplicationContext for singletons that need Context.
29
+ - Use @ActivityContext only in @ActivityScoped or narrower components.
30
+
31
+ ## Custom Scopes
32
+ - Define custom scopes with @Scope annotation for domain-specific lifetimes.
33
+ - Map to custom Hilt components with @DefineComponent.
34
+ - Rarely needed — standard Hilt scopes cover most cases.
@@ -0,0 +1,36 @@
1
+ # Testing with DI
2
+
3
+ ## Unit Tests
4
+ - No Hilt needed — use constructor injection with fakes/mocks.
5
+ - Create fakes of interfaces defined in feature-api modules.
6
+ - Instantiate ViewModel/UseCase directly with fake dependencies.
7
+ - This is the primary reason to use constructor injection everywhere.
8
+
9
+ ## Instrumented Tests
10
+ - @HiltAndroidTest on test class.
11
+ - Add HiltAndroidRule as a JUnit rule — must be ordered before other rules.
12
+ - Use hiltRule.inject() in @Before to trigger injection.
13
+ - Test Activity/Fragment with launchActivity or launchFragmentInHiltContainer.
14
+
15
+ ## Replacing Bindings
16
+ - @UninstallModules(ProductionModule::class) removes production bindings.
17
+ - Provide test bindings in a @Module @InstallIn @TestInstallIn annotated class.
18
+ - Or use @BindValue to replace a single binding with a field in the test class.
19
+ - @TestInstallIn replaces globally — @UninstallModules + local @Module for per-test replacement.
20
+
21
+ ## Custom Test Components
22
+ - Use @CustomTestApplication for tests that need a custom Application class.
23
+ - Combine with @HiltAndroidTest for full DI in custom app contexts.
24
+ - Use HiltTestApplication as the application class in test runner config.
25
+
26
+ ## Robolectric
27
+ - Hilt works with Robolectric — use @HiltAndroidTest + @Config(application = HiltTestApplication::class).
28
+ - Combine with RobolectricTestRunner.
29
+ - Faster than instrumented tests — runs on JVM.
30
+ - Some Hilt features may require additional Robolectric configuration.
31
+
32
+ ## Best Practices
33
+ - Test business logic without DI framework — pure unit tests.
34
+ - Use DI in tests only when testing integration points (Activity, Fragment, Service).
35
+ - Keep test modules simple — prefer @BindValue over full module replacement.
36
+ - Verify DI graph compiles in CI — Hilt catches missing bindings at compile time.
@@ -0,0 +1,36 @@
1
+
2
+ ---
3
+ name: android-local-storage
4
+ description: Local storage — Room, DataStore, offline-first architecture, caching, encryption.
5
+ ---
6
+
7
+ # Android Local Storage
8
+
9
+ Cross-cutting skill — always activates alongside the project-type-specific skill.
10
+
11
+ ## Hard Rules
12
+ - Use Room for structured relational data — not raw SQLite.
13
+ - Use DataStore (Preferences or Proto) for key-value data — not SharedPreferences.
14
+ - Export Room schemas (exportSchema = true) and test all migrations.
15
+ - Never perform database operations on the main thread.
16
+ - Use Flow or LiveData for reactive database queries — not one-shot reads for UI.
17
+ - Define a single source of truth (database) — network responses update the database, UI observes the database.
18
+ - Never store sensitive data (tokens, passwords) in Room or DataStore without encryption.
19
+ - Use transactions for multi-table write operations.
20
+ - Keep entities flat — avoid deeply nested objects in Room.
21
+ - Use TypeConverters sparingly — prefer normalized relational design.
22
+
23
+ ## Core Patterns
24
+ - Repository pattern: database as the source of truth, network as the updater.
25
+ - Room DAOs return Flow<List<T>> for reactive UI updates.
26
+ - Use @Upsert for insert-or-update operations (Room 2.5+).
27
+ - DataStore with Proto for type-safe structured preferences.
28
+ - Implement cache expiry with timestamps — stale-while-revalidate pattern.
29
+ - Use database-backed pagination with RemoteMediator + Paging 3.
30
+
31
+ ## References
32
+ - references/room_patterns.md
33
+ - references/datastore.md
34
+ - references/offline_first.md
35
+ - references/cache_strategies.md
36
+ - references/encryption.md
@@ -0,0 +1,33 @@
1
+ # Cache Strategies
2
+
3
+ ## Time-Based Expiry
4
+ - Store cachedAt timestamp alongside cached data.
5
+ - Check freshness: if (now - cachedAt > maxAge) refresh from network.
6
+ - Different TTLs for different data: user profile (1 hour), feed (5 minutes), config (24 hours).
7
+ - Use stale-while-revalidate: show stale data immediately, refresh in background.
8
+
9
+ ## LRU Cache
10
+ - In-memory LRU cache for frequently accessed data.
11
+ - Use LruCache from android.util or custom implementation.
12
+ - Size-based eviction — define max entries or max memory.
13
+ - Use as L1 cache (memory) backed by L2 cache (database).
14
+
15
+ ## ETag / Conditional Requests
16
+ - Store ETag from server response alongside cached data.
17
+ - Send If-None-Match header on next request.
18
+ - 304 Not Modified: cache is still valid, no data transfer.
19
+ - Reduces bandwidth while keeping data fresh.
20
+
21
+ ## Cache Invalidation
22
+ - User action: pull-to-refresh, data mutation, logout.
23
+ - Push notification: server signals data change via FCM.
24
+ - Time-based: automatic expiry after TTL.
25
+ - Event-based: invalidate related caches when a mutation occurs.
26
+ - Prefer explicit invalidation over time-based for user-facing data.
27
+
28
+ ## Multi-Layer Cache
29
+ - L1: in-memory (fast, small, lost on process death).
30
+ - L2: database/disk (slower, persistent across process restarts).
31
+ - L3: network (slowest, always fresh).
32
+ - Read: check L1 → L2 → L3. Write: update all layers.
33
+ - Use for: image caching (Coil/Glide handle this), API response caching, computed results.
@@ -0,0 +1,35 @@
1
+ # DataStore
2
+
3
+ ## Preferences DataStore
4
+ - Replacement for SharedPreferences — coroutine and Flow-based.
5
+ - Create with preferencesDataStore(name = "settings") delegate.
6
+ - Read: dataStore.data.map { prefs -> prefs[KEY] }.
7
+ - Write: dataStore.edit { prefs -> prefs[KEY] = value }.
8
+ - Keys: stringPreferencesKey, intPreferencesKey, booleanPreferencesKey, etc.
9
+
10
+ ## Proto DataStore
11
+ - Type-safe structured data — define schema with Protocol Buffers.
12
+ - Create .proto file in src/main/proto/.
13
+ - Implement Serializer<T> for read/write.
14
+ - Read/write are strongly typed — no string keys.
15
+ - Prefer Proto DataStore for complex settings or data with multiple fields.
16
+
17
+ ## Migration from SharedPreferences
18
+ - Use SharedPreferencesMigration in DataStore builder.
19
+ - Migration runs once — old SharedPreferences deleted after migration.
20
+ - Handle migration failures — provide default values.
21
+ - Test migration with both old and new data formats.
22
+
23
+ ## Best Practices
24
+ - Single DataStore instance per file — create at top level with delegate.
25
+ - Never create DataStore inside Activity/Fragment — use singleton pattern.
26
+ - Handle IOException in data.catch { } — file corruption is possible.
27
+ - Emit default value on error: .catch { emit(emptyPreferences()) }.
28
+ - DataStore writes are atomic — no partial writes.
29
+ - Do not use DataStore for large datasets — use Room instead.
30
+
31
+ ## Thread Safety
32
+ - DataStore is thread-safe — concurrent reads and writes are safe.
33
+ - Writes are serialized — ordered by call sequence.
34
+ - Reads are non-blocking — observe via Flow.
35
+ - No need for synchronized blocks or mutexes.
@@ -0,0 +1,35 @@
1
+ # Storage Encryption
2
+
3
+ ## EncryptedSharedPreferences
4
+ - Use for key-value secrets (tokens, API keys, small sensitive data).
5
+ - Backed by AES256-SIV (keys) and AES256-GCM (values).
6
+ - Create with MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS).
7
+ - Thread-safe but slower than regular SharedPreferences.
8
+ - Migrate from regular SharedPreferences when adding encryption.
9
+
10
+ ## EncryptedFile
11
+ - Use for file-level encryption (documents, exported data).
12
+ - Streaming encryption — suitable for large files.
13
+ - Same MasterKey as EncryptedSharedPreferences.
14
+ - Use for: database exports, log files, downloaded sensitive content.
15
+
16
+ ## SQLCipher for Room
17
+ - SQLCipher encrypts the entire Room database file.
18
+ - Use android-database-sqlcipher dependency + SupportFactory.
19
+ - Pass encryption key via SupportFactory(passphrase).
20
+ - Store passphrase in Android Keystore — not hardcoded.
21
+ - Performance impact: ~5-15% slower than unencrypted Room.
22
+
23
+ ## Android Keystore
24
+ - Hardware-backed key storage (TEE/StrongBox).
25
+ - Generate keys with KeyGenParameterSpec.
26
+ - Keys never leave the secure hardware.
27
+ - Use for: encrypting local secrets, biometric-bound operations.
28
+ - Keys are not exportable — use Keystore for crypto operations only.
29
+
30
+ ## Best Practices
31
+ - Encrypt tokens, passwords, PII, health data, financial data.
32
+ - Do not encrypt non-sensitive data — unnecessary performance cost.
33
+ - Wipe decrypted data from memory after use (overwrite byte arrays).
34
+ - Handle KeyPermanentlyInvalidatedException when biometric enrollment changes.
35
+ - Test encryption on devices with and without hardware-backed Keystore.
@@ -0,0 +1,39 @@
1
+ # Offline-First Architecture
2
+
3
+ ## Single Source of Truth
4
+ - Database (Room) is the single source of truth — UI always reads from database.
5
+ - Network responses update the database — never displayed directly to UI.
6
+ - Flow: API → Repository → Database → UI observes database.
7
+ - Benefits: offline access, consistent state, no stale UI.
8
+
9
+ ## Repository Pattern
10
+ - Repository exposes Flow<List<T>> from Room DAO.
11
+ - Repository has a refresh() suspend function that fetches from network and updates database.
12
+ - UI calls refresh() on pull-to-refresh or initial load.
13
+ - Database Flow automatically re-emits when data changes.
14
+
15
+ ## NetworkBoundResource Pattern
16
+ - Observe database (cache).
17
+ - If cache is stale or empty, fetch from network.
18
+ - Save network response to database.
19
+ - Re-emit updated data from database.
20
+ - Handle loading, success, and error states.
21
+
22
+ ## Paging with RemoteMediator
23
+ - Use Paging 3 + RemoteMediator for paginated offline-first lists.
24
+ - RemoteMediator fetches pages from network, stores in Room.
25
+ - PagingSource reads from Room for UI.
26
+ - Room PagingSource auto-invalidates when data changes.
27
+ - Handle PREPEND, APPEND, and REFRESH load types.
28
+
29
+ ## Conflict Resolution
30
+ - Last-write-wins: server timestamp determines which version to keep.
31
+ - Client-wins: local changes always override server data.
32
+ - Server-wins: server data always overrides local changes.
33
+ - Choose based on data type — user-generated content needs careful resolution.
34
+
35
+ ## Sync Strategy
36
+ - Eager: sync immediately when network is available.
37
+ - Lazy: sync on demand (user opens screen, pull-to-refresh).
38
+ - Periodic: sync on schedule using WorkManager.
39
+ - Push-triggered: sync when FCM notification arrives.
@@ -0,0 +1,34 @@
1
+ # Room Patterns
2
+
3
+ ## Database Setup
4
+ - Annotate with @Database(entities = [...], version = N, exportSchema = true).
5
+ - Use singleton pattern: companion object with @Volatile instance + synchronized.
6
+ - Or provide via Hilt @Singleton @Provides.
7
+ - Add fallbackToDestructiveMigration() only for cache databases — never for user data.
8
+ - Configure WAL mode (default on API 16+) for better concurrent read/write.
9
+
10
+ ## Entities
11
+ - @Entity with @PrimaryKey — prefer autoGenerate = true for local IDs.
12
+ - Use @ColumnInfo for custom column names.
13
+ - @Embedded for flattening nested objects into the same table.
14
+ - @TypeConverter for complex types (Date, Enum, List) — register in @Database.
15
+ - Keep entities flat — deeply nested objects should be separate entities with relations.
16
+
17
+ ## DAOs
18
+ - Return Flow<List<T>> for reactive queries — Room re-emits on table changes.
19
+ - Use suspend for write operations (insert, update, delete).
20
+ - @Upsert (Room 2.5+) for insert-or-update in one operation.
21
+ - @Transaction for multi-table operations.
22
+ - @RawQuery for dynamic queries — use sparingly, prefer type-safe DAO methods.
23
+
24
+ ## Relations
25
+ - @Relation for one-to-many and many-to-many relationships.
26
+ - Use intermediary data classes with @Embedded parent + @Relation children.
27
+ - @Junction for many-to-many with a junction table.
28
+ - Always use @Transaction on queries with @Relation — ensures consistency.
29
+
30
+ ## Migrations
31
+ - Provide Migration(oldVersion, newVersion) with SQL statements.
32
+ - Test every migration path with MigrationTestHelper.
33
+ - Use @AutoMigration for simple changes (add column, add table).
34
+ - Never use fallbackToDestructiveMigration for databases with user data.
@@ -0,0 +1,35 @@
1
+
2
+ ---
3
+ name: android-maps-location
4
+ description: Maps & location — Google Maps SDK, FusedLocationProvider, geofencing, permissions.
5
+ ---
6
+
7
+ # Android Maps & Location
8
+
9
+ Cross-cutting skill — always activates alongside the project-type-specific skill.
10
+
11
+ ## Hard Rules
12
+ - Use FusedLocationProviderClient — not LocationManager directly.
13
+ - Request only the location accuracy you need (COARSE vs FINE).
14
+ - Handle both approximate (COARSE) and precise (FINE) location grants (API 31+).
15
+ - Remove location updates when not needed — do not leak location listeners.
16
+ - Use foreground service with location type for background location access.
17
+ - ACCESS_BACKGROUND_LOCATION requires separate permission request and justification.
18
+ - Protect Google Maps API key with app restriction (SHA-1 + package name) in Cloud Console.
19
+ - Do not hardcode API keys in source — use Secrets Gradle Plugin or local.properties.
20
+ - Handle location permission denial gracefully — degrade to manual location entry.
21
+ - Test with mock locations enabled and disabled.
22
+
23
+ ## Core Patterns
24
+ - Request FINE + COARSE together — user can downgrade to approximate on API 31+.
25
+ - Use LocationRequest.Builder with appropriate priority and interval.
26
+ - Prefer geofencing over continuous polling for location-triggered actions.
27
+ - Use Maps Compose library for Compose integration.
28
+ - Cluster markers for dense map points — avoid rendering thousands of markers.
29
+ - Cache geocoding results — avoid repeated API calls for the same coordinates.
30
+
31
+ ## References
32
+ - references/google_maps.md
33
+ - references/fused_location.md
34
+ - references/geofencing.md
35
+ - references/location_permissions.md
@@ -0,0 +1,40 @@
1
+ # Fused Location Provider
2
+
3
+ ## Setup
4
+ - Use com.google.android.gms:play-services-location dependency.
5
+ - Get client: LocationServices.getFusedLocationProviderClient(context).
6
+ - Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission.
7
+ - Check permission before every location request.
8
+
9
+ ## Last Known Location
10
+ - getLastLocation(): fast, no power cost, may return null.
11
+ - Returns null if: location turned off, device just booted, Google Play Services data cleared.
12
+ - Use as initial location while waiting for fresh updates.
13
+ - Always handle null — don't assume location is available.
14
+
15
+ ## Location Updates
16
+ - Build LocationRequest with Priority and interval.
17
+ - PRIORITY_HIGH_ACCURACY: GPS + network (most power, ~1m accuracy).
18
+ - PRIORITY_BALANCED_POWER_ACCURACY: network-based (~100m, lower power).
19
+ - PRIORITY_LOW_POWER: passive, minimal power (~1km accuracy).
20
+ - PRIORITY_PASSIVE: only receive locations from other apps' requests.
21
+
22
+ ## Request Configuration
23
+ - setIntervalMillis: desired update interval.
24
+ - setMinUpdateIntervalMillis: fastest acceptable interval.
25
+ - setMaxUpdateDelayMillis: batch delivery delay for power saving.
26
+ - setMinUpdateDistanceMeters: minimum displacement for update.
27
+ - Use setWaitForAccurateLocation(true) for initial high-accuracy fix.
28
+
29
+ ## Receiving Updates
30
+ - requestLocationUpdates(request, callback, looper) for callback-based.
31
+ - requestLocationUpdates(request, pendingIntent) for background delivery.
32
+ - Always call removeLocationUpdates() when done.
33
+ - Use callbackFlow for coroutine/Flow integration.
34
+
35
+ ## Best Practices
36
+ - Request lowest acceptable priority — save battery.
37
+ - Remove updates in onPause/onStop — unless background location is needed.
38
+ - Background location requires foreground service with location type (API 29+).
39
+ - ACCESS_BACKGROUND_LOCATION is a separate permission request.
40
+ - Handle location settings: use SettingsClient.checkLocationSettings() and prompt user.
@@ -0,0 +1,36 @@
1
+ # Geofencing
2
+
3
+ ## Setup
4
+ - Use GeofencingClient from play-services-location.
5
+ - Requires ACCESS_FINE_LOCATION (and ACCESS_BACKGROUND_LOCATION for background).
6
+ - Maximum 100 geofences per app per device.
7
+ - Geofences are lost on reboot — re-register in BOOT_COMPLETED receiver.
8
+
9
+ ## Creating Geofences
10
+ - Geofence.Builder() with requestId, circularRegion(lat, lng, radius), expirationDuration.
11
+ - Transition types: GEOFENCE_TRANSITION_ENTER, EXIT, DWELL.
12
+ - setLoiteringDelay() for DWELL transitions — how long user must stay.
13
+ - Minimum reliable radius: ~100m (smaller radii are unreliable).
14
+ - Use unique requestId for each geofence — needed for removal.
15
+
16
+ ## Registering
17
+ - Build GeofencingRequest with addGeofences() and initial trigger.
18
+ - INITIAL_TRIGGER_ENTER: trigger if already inside geofence.
19
+ - INITIAL_TRIGGER_DWELL: trigger if already dwelling.
20
+ - Register with addGeofences(request, pendingIntent).
21
+ - PendingIntent delivers to BroadcastReceiver or Service.
22
+
23
+ ## Handling Transitions
24
+ - Create a BroadcastReceiver to handle geofence events.
25
+ - Extract GeofencingEvent from Intent: GeofencingEvent.fromIntent(intent).
26
+ - Check for errors: geofencingEvent.hasError().
27
+ - Get transition type and triggering geofences from the event.
28
+ - Post notification or trigger WorkManager task on transition.
29
+
30
+ ## Best Practices
31
+ - Use geofencing instead of continuous location polling — much lower power.
32
+ - Keep radius ≥ 100m for reliable detection.
33
+ - Handle Geofence expiration — re-register if long-lived.
34
+ - Test with mock locations — real geofence testing is slow.
35
+ - Handle permission denial — geofencing requires background location for useful behavior.
36
+ - Re-register geofences on app update and device reboot.
@@ -0,0 +1,39 @@
1
+ # Google Maps SDK
2
+
3
+ ## Setup
4
+ - Add com.google.android.gms:play-services-maps dependency.
5
+ - Add API key in AndroidManifest.xml: <meta-data android:name="com.google.android.geo.API_KEY" android:value="${MAPS_API_KEY}" />.
6
+ - Inject API key from local.properties or CI secrets via Secrets Gradle Plugin.
7
+ - Restrict API key in Google Cloud Console: Android app restriction + Maps SDK API restriction.
8
+
9
+ ## Maps Compose
10
+ - Use maps-compose library for Compose integration.
11
+ - GoogleMap composable with CameraPositionState.
12
+ - Marker(state = MarkerState(position = latLng), title = "Label").
13
+ - rememberCameraPositionState for controlling camera position.
14
+ - Use MapProperties for map type, gestures, and controls.
15
+
16
+ ## Markers
17
+ - Use Marker composable for individual points.
18
+ - MarkerState for position — can be animated.
19
+ - Custom marker icons: BitmapDescriptorFactory.fromResource or fromBitmap.
20
+ - Use clustering for dense marker sets: maps-utils library + Clustering composable.
21
+ - InfoWindow for tap-to-reveal details on markers.
22
+
23
+ ## Camera Control
24
+ - CameraUpdateFactory.newLatLngZoom(position, zoom) for programmatic movement.
25
+ - Animate: cameraPositionState.animate(cameraUpdate, durationMs).
26
+ - Set bounds: CameraUpdateFactory.newLatLngBounds(bounds, padding) to fit all markers.
27
+ - Handle camera move events: onCameraMove callback.
28
+
29
+ ## Styling
30
+ - Use MapStyleOptions for custom map styling (JSON style).
31
+ - Cloud-based map styling for dynamic style updates.
32
+ - Dark mode: apply dark map style when app is in dark theme.
33
+ - Hide/show map features: POIs, transit, roads, labels.
34
+
35
+ ## Best Practices
36
+ - Load map lazily — don't initialize until the map screen is visible.
37
+ - Handle Google Play Services unavailability gracefully.
38
+ - Set initial camera position from user's last known location.
39
+ - Test on devices without Google Play Services (Huawei, etc.) — provide fallback.