@bricks-soft/capacitor-location-tracking 0.0.0-stage → 8.0.1
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.
- package/LICENSE +21 -0
- package/README.md +2759 -2
- package/android/build.gradle +107 -0
- package/android/consumer-rules.pro +42 -0
- package/android/src/main/AndroidManifest.xml +52 -0
- package/android/src/main/java/com/brickssoft/locationtracking/LocationTrackingPlugin.kt +431 -0
- package/android/src/main/java/com/brickssoft/locationtracking/api/LocationTrackingListener.kt +52 -0
- package/android/src/main/java/com/brickssoft/locationtracking/api/LocationTrackingNative.kt +267 -0
- package/android/src/main/java/com/brickssoft/locationtracking/api/NativeListeners.kt +270 -0
- package/android/src/main/java/com/brickssoft/locationtracking/api/NativeThread.kt +57 -0
- package/android/src/main/java/com/brickssoft/locationtracking/bridge/BridgeServices.kt +64 -0
- package/android/src/main/java/com/brickssoft/locationtracking/bridge/CallResponder.kt +41 -0
- package/android/src/main/java/com/brickssoft/locationtracking/bridge/OptionParsers.kt +281 -0
- package/android/src/main/java/com/brickssoft/locationtracking/bridge/PluginHandlers.kt +541 -0
- package/android/src/main/java/com/brickssoft/locationtracking/bridge/PluginPermissionHost.kt +76 -0
- package/android/src/main/java/com/brickssoft/locationtracking/bridge/WatchRegistry.kt +84 -0
- package/android/src/main/java/com/brickssoft/locationtracking/config/Config.kt +231 -0
- package/android/src/main/java/com/brickssoft/locationtracking/config/ConfigJson.kt +574 -0
- package/android/src/main/java/com/brickssoft/locationtracking/config/ConfigStore.kt +31 -0
- package/android/src/main/java/com/brickssoft/locationtracking/config/ConfigValidator.kt +170 -0
- package/android/src/main/java/com/brickssoft/locationtracking/config/RuntimeStateJson.kt +73 -0
- package/android/src/main/java/com/brickssoft/locationtracking/config/SharedPrefsConfigStore.kt +135 -0
- package/android/src/main/java/com/brickssoft/locationtracking/config/State.kt +45 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/AppDispatchers.kt +21 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/Clock.kt +41 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/Components.kt +217 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/Constants.kt +78 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/Errors.kt +27 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/EventBus.kt +39 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/ForceStopProbe.kt +63 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/Iso8601.kt +63 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/Logger.kt +68 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/RecordHooks.kt +47 -0
- package/android/src/main/java/com/brickssoft/locationtracking/core/TrackingEvent.kt +64 -0
- package/android/src/main/java/com/brickssoft/locationtracking/data/SqlSupport.kt +79 -0
- package/android/src/main/java/com/brickssoft/locationtracking/data/SqliteGeofenceStore.kt +144 -0
- package/android/src/main/java/com/brickssoft/locationtracking/data/SqliteLocationStore.kt +215 -0
- package/android/src/main/java/com/brickssoft/locationtracking/data/Stores.kt +45 -0
- package/android/src/main/java/com/brickssoft/locationtracking/data/TrackingDatabase.kt +111 -0
- package/android/src/main/java/com/brickssoft/locationtracking/device/DefaultDeviceInfoProvider.kt +104 -0
- package/android/src/main/java/com/brickssoft/locationtracking/device/DefaultDeviceMonitor.kt +335 -0
- package/android/src/main/java/com/brickssoft/locationtracking/device/DeviceMonitor.kt +36 -0
- package/android/src/main/java/com/brickssoft/locationtracking/device/DeviceStateMapping.kt +69 -0
- package/android/src/main/java/com/brickssoft/locationtracking/engine/DefaultTrackingEngine.kt +1281 -0
- package/android/src/main/java/com/brickssoft/locationtracking/engine/ElasticDistance.kt +68 -0
- package/android/src/main/java/com/brickssoft/locationtracking/engine/LocationRequests.kt +74 -0
- package/android/src/main/java/com/brickssoft/locationtracking/engine/MotionStateMachine.kt +291 -0
- package/android/src/main/java/com/brickssoft/locationtracking/engine/StationaryRegion.kt +41 -0
- package/android/src/main/java/com/brickssoft/locationtracking/engine/TrackingEngine.kt +60 -0
- package/android/src/main/java/com/brickssoft/locationtracking/engine/TrackingTimers.kt +90 -0
- package/android/src/main/java/com/brickssoft/locationtracking/geofence/DefaultGeofenceManager.kt +899 -0
- package/android/src/main/java/com/brickssoft/locationtracking/geofence/DwellTracker.kt +80 -0
- package/android/src/main/java/com/brickssoft/locationtracking/geofence/GeofenceManager.kt +33 -0
- package/android/src/main/java/com/brickssoft/locationtracking/geofence/PolygonMath.kt +194 -0
- package/android/src/main/java/com/brickssoft/locationtracking/heartbeat/DefaultHeartbeatScheduler.kt +713 -0
- package/android/src/main/java/com/brickssoft/locationtracking/heartbeat/HeartbeatAlarmReceiver.kt +69 -0
- package/android/src/main/java/com/brickssoft/locationtracking/heartbeat/HeartbeatAlarms.kt +100 -0
- package/android/src/main/java/com/brickssoft/locationtracking/heartbeat/HeartbeatScheduler.kt +25 -0
- package/android/src/main/java/com/brickssoft/locationtracking/heartbeat/HeartbeatWindow.kt +179 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/AuthorizationManager.kt +213 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/BodyBuilder.kt +73 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/HttpSupport.kt +118 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/HttpSyncer.kt +18 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/OkHttpSyncer.kt +551 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/StrictJson.kt +135 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/SyncPolicy.kt +109 -0
- package/android/src/main/java/com/brickssoft/locationtracking/http/TemplateRenderer.kt +143 -0
- package/android/src/main/java/com/brickssoft/locationtracking/logging/FileLogger.kt +461 -0
- package/android/src/main/java/com/brickssoft/locationtracking/logging/LogFileProvider.kt +9 -0
- package/android/src/main/java/com/brickssoft/locationtracking/logging/LogFormatter.kt +148 -0
- package/android/src/main/java/com/brickssoft/locationtracking/logging/LogStore.kt +30 -0
- package/android/src/main/java/com/brickssoft/locationtracking/model/DeviceModels.kt +176 -0
- package/android/src/main/java/com/brickssoft/locationtracking/model/GeofenceSpec.kt +25 -0
- package/android/src/main/java/com/brickssoft/locationtracking/model/ModelJson.kt +550 -0
- package/android/src/main/java/com/brickssoft/locationtracking/model/Record.kt +106 -0
- package/android/src/main/java/com/brickssoft/locationtracking/model/TrackedLocation.kt +53 -0
- package/android/src/main/java/com/brickssoft/locationtracking/permission/BackgroundRationaleDialog.kt +85 -0
- package/android/src/main/java/com/brickssoft/locationtracking/permission/CurrentActivityTracker.kt +72 -0
- package/android/src/main/java/com/brickssoft/locationtracking/permission/DefaultPermissionManager.kt +333 -0
- package/android/src/main/java/com/brickssoft/locationtracking/permission/PermissionManager.kt +54 -0
- package/android/src/main/java/com/brickssoft/locationtracking/position/DefaultPositionService.kt +277 -0
- package/android/src/main/java/com/brickssoft/locationtracking/position/PositionService.kt +39 -0
- package/android/src/main/java/com/brickssoft/locationtracking/position/PositionWatch.kt +115 -0
- package/android/src/main/java/com/brickssoft/locationtracking/processing/DefaultLocationProcessor.kt +93 -0
- package/android/src/main/java/com/brickssoft/locationtracking/processing/DefaultOdometer.kt +99 -0
- package/android/src/main/java/com/brickssoft/locationtracking/processing/DefaultRecordFactory.kt +166 -0
- package/android/src/main/java/com/brickssoft/locationtracking/processing/Geo.kt +56 -0
- package/android/src/main/java/com/brickssoft/locationtracking/processing/KalmanFilter.kt +72 -0
- package/android/src/main/java/com/brickssoft/locationtracking/processing/Processing.kt +48 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/Backends.kt +187 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/DefaultProviderFactory.kt +169 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/ProviderPackaging.kt +135 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/android/AndroidActivityBackend.kt +25 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/android/AndroidGeofenceBackend.kt +181 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/android/AndroidGeofenceReceiver.kt +115 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/android/AndroidLocationBackend.kt +265 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/android/AndroidProviderBundle.kt +31 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/android/LocationProviders.kt +98 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsActivityBackend.kt +80 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsActivityReceiver.kt +62 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsErrors.kt +72 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsGeofenceBackend.kt +152 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsGeofenceReceiver.kt +78 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsLocationBackend.kt +176 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsProviderBundle.kt +62 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsReceiverSupport.kt +88 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/gms/GmsTasks.kt +55 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsActivityBackend.kt +71 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsActivityReceiver.kt +57 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsErrors.kt +76 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsGeofenceBackend.kt +116 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsGeofenceReceiver.kt +67 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsIntents.kt +83 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsLocationBackend.kt +197 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsProviderBundle.kt +55 -0
- package/android/src/main/java/com/brickssoft/locationtracking/provider/hms/HmsTasks.kt +44 -0
- package/android/src/main/java/com/brickssoft/locationtracking/record/RecordSink.kt +95 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/BootCountStore.kt +44 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/BootReceiver.kt +175 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/DefaultServiceController.kt +196 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/LocationTrackingService.kt +319 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/NotificationActionReceiver.kt +42 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/NotificationFactory.kt +338 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/ServiceCommands.kt +204 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/ServiceController.kt +22 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/ServiceDeps.kt +61 -0
- package/android/src/main/java/com/brickssoft/locationtracking/service/WhileInUseStartCheck.kt +115 -0
- package/android/src/main/java/com/brickssoft/locationtracking/settings/DefaultDeviceSettings.kt +79 -0
- package/android/src/main/java/com/brickssoft/locationtracking/settings/DeviceSettings.kt +21 -0
- package/android/src/main/java/com/brickssoft/locationtracking/settings/OemPowerManagers.kt +198 -0
- package/android/src/main/res/drawable/lt_ic_notification.xml +11 -0
- package/android/src/main/res/values/lt_strings.xml +11 -0
- package/android/src/main/res/xml/lt_file_paths.xml +5 -0
- package/dist/esm/definitions.d.ts +719 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/events.d.ts +50 -0
- package/dist/esm/events.js +52 -0
- package/dist/esm/events.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/plugin.d.ts +3 -0
- package/dist/esm/plugin.js +10 -0
- package/dist/esm/plugin.js.map +1 -0
- package/dist/esm/web/config.d.ts +19 -0
- package/dist/esm/web/config.js +243 -0
- package/dist/esm/web/config.js.map +1 -0
- package/dist/esm/web/device.d.ts +9 -0
- package/dist/esm/web/device.js +90 -0
- package/dist/esm/web/device.js.map +1 -0
- package/dist/esm/web/errors.d.ts +14 -0
- package/dist/esm/web/errors.js +19 -0
- package/dist/esm/web/errors.js.map +1 -0
- package/dist/esm/web/geolocation.d.ts +26 -0
- package/dist/esm/web/geolocation.js +117 -0
- package/dist/esm/web/geolocation.js.map +1 -0
- package/dist/esm/web/location.d.ts +7 -0
- package/dist/esm/web/location.js +70 -0
- package/dist/esm/web/location.js.map +1 -0
- package/dist/esm/web.d.ts +164 -0
- package/dist/esm/web.js +328 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +945 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +948 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +60 -4
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
|
4
|
+
androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.17.0'
|
|
5
|
+
playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '21.3.0'
|
|
6
|
+
hmsLocationVersion = project.hasProperty('hmsLocationVersion') ? rootProject.ext.hmsLocationVersion : '6.16.0.302'
|
|
7
|
+
kotlinxCoroutinesVersion = project.hasProperty('kotlinxCoroutinesVersion') ? rootProject.ext.kotlinxCoroutinesVersion : '1.10.2'
|
|
8
|
+
okhttpVersion = '4.12.0'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
buildscript {
|
|
12
|
+
ext.kotlin_version = project.hasProperty('kotlin_version') ? rootProject.ext.kotlin_version : '2.2.20'
|
|
13
|
+
repositories {
|
|
14
|
+
google()
|
|
15
|
+
mavenCentral()
|
|
16
|
+
}
|
|
17
|
+
dependencies {
|
|
18
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
19
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
apply plugin: 'com.android.library'
|
|
24
|
+
if (project.extensions.findByName('kotlin') == null) {
|
|
25
|
+
apply plugin: 'kotlin-android'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Which location SDKs are packaged into the app: -PlocationTracking.providers=gms,hms (default: gms).
|
|
29
|
+
// The plugin always compiles against both (compileOnly) and selects one at runtime via reflection.
|
|
30
|
+
// An app with Play and AppGallery product flavors sets `none` and adds the SDKs per flavor itself (README).
|
|
31
|
+
def ltProviders = (project.findProperty('locationTracking.providers') ?: 'gms').toString()
|
|
32
|
+
.split(',').collect { it.trim().toLowerCase() }.findAll { it && it != 'none' }.toSet()
|
|
33
|
+
|
|
34
|
+
android {
|
|
35
|
+
namespace = 'com.brickssoft.locationtracking'
|
|
36
|
+
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
37
|
+
resourcePrefix 'lt_'
|
|
38
|
+
defaultConfig {
|
|
39
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
|
40
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
|
41
|
+
consumerProguardFiles 'consumer-rules.pro'
|
|
42
|
+
// package.json ships next to android/ in the npm package, so it is the one place the version is set.
|
|
43
|
+
buildConfigField 'String', 'PLUGIN_VERSION', "\"${new groovy.json.JsonSlurper().parse(file('../package.json')).version}\""
|
|
44
|
+
}
|
|
45
|
+
buildFeatures {
|
|
46
|
+
buildConfig = true
|
|
47
|
+
}
|
|
48
|
+
buildTypes {
|
|
49
|
+
release {
|
|
50
|
+
minifyEnabled false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
compileOptions {
|
|
54
|
+
sourceCompatibility JavaVersion.VERSION_21
|
|
55
|
+
targetCompatibility JavaVersion.VERSION_21
|
|
56
|
+
}
|
|
57
|
+
lint {
|
|
58
|
+
abortOnError = false
|
|
59
|
+
}
|
|
60
|
+
testOptions {
|
|
61
|
+
unitTests {
|
|
62
|
+
includeAndroidResources = true
|
|
63
|
+
returnDefaultValues = true
|
|
64
|
+
all {
|
|
65
|
+
maxHeapSize = '1024m'
|
|
66
|
+
maxParallelForks = 1
|
|
67
|
+
jvmArgs '-XX:+UseSerialGC', '-XX:+EnableDynamicAgentLoading'
|
|
68
|
+
testLogging {
|
|
69
|
+
events 'failed'
|
|
70
|
+
exceptionFormat 'full'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
kotlin {
|
|
78
|
+
jvmToolchain(21)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
repositories {
|
|
82
|
+
google()
|
|
83
|
+
mavenCentral()
|
|
84
|
+
maven { url = 'https://developer.huawei.com/repo/' }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
dependencies {
|
|
88
|
+
implementation project(':capacitor-android')
|
|
89
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
90
|
+
implementation "androidx.core:core-ktx:$androidxCoreKTXVersion"
|
|
91
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinxCoroutinesVersion"
|
|
92
|
+
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
|
93
|
+
|
|
94
|
+
compileOnly "com.google.android.gms:play-services-location:$playServicesLocationVersion"
|
|
95
|
+
compileOnly "com.huawei.hms:location:$hmsLocationVersion"
|
|
96
|
+
if (ltProviders.contains('gms')) implementation "com.google.android.gms:play-services-location:$playServicesLocationVersion"
|
|
97
|
+
if (ltProviders.contains('hms')) implementation "com.huawei.hms:location:$hmsLocationVersion"
|
|
98
|
+
|
|
99
|
+
testImplementation "junit:junit:$junitVersion"
|
|
100
|
+
testImplementation 'org.robolectric:robolectric:4.16.1'
|
|
101
|
+
testImplementation 'androidx.test:core-ktx:1.7.0'
|
|
102
|
+
testImplementation 'io.mockk:mockk:1.14.6'
|
|
103
|
+
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinxCoroutinesVersion"
|
|
104
|
+
testImplementation "com.squareup.okhttp3:mockwebserver:$okhttpVersion"
|
|
105
|
+
testImplementation "com.google.android.gms:play-services-location:$playServicesLocationVersion"
|
|
106
|
+
testImplementation "com.huawei.hms:location:$hmsLocationVersion"
|
|
107
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Consumer ProGuard/R8 rules for @bricks-soft/capacitor-location-tracking.
|
|
2
|
+
|
|
3
|
+
# The plugin compiles against both location SDKs (compileOnly); an app may package only one of them.
|
|
4
|
+
-dontwarn com.google.android.gms.**
|
|
5
|
+
-dontwarn com.huawei.**
|
|
6
|
+
|
|
7
|
+
# Provider bundles are instantiated reflectively by DefaultProviderFactory.
|
|
8
|
+
-keep class com.brickssoft.locationtracking.provider.**.*ProviderBundle {
|
|
9
|
+
public <init>(android.content.Context);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# DefaultProviderFactory probes for the packaged SDKs by class name (Class.forName). Keep those names, or a
|
|
13
|
+
# minified release app would never detect Google Play services and fall back to the Android backend.
|
|
14
|
+
-keepnames class com.google.android.gms.location.LocationServices
|
|
15
|
+
-keepnames class com.google.android.gms.common.GoogleApiAvailability
|
|
16
|
+
-keepnames class com.huawei.hms.location.LocationServices
|
|
17
|
+
|
|
18
|
+
# Companion native API (docs/native-api.md): companion plugins and app code call these classes and interfaces. Keep
|
|
19
|
+
# every public member of the package, and the error type its callbacks deliver (TrackingException with an ErrorCode),
|
|
20
|
+
# so a companion library that is shrunk separately still finds them.
|
|
21
|
+
-keep class com.brickssoft.locationtracking.api.** { public *; }
|
|
22
|
+
-keep class com.brickssoft.locationtracking.core.TrackingException { public *; }
|
|
23
|
+
-keep class com.brickssoft.locationtracking.core.ErrorCode { public *; }
|
|
24
|
+
|
|
25
|
+
# Listener classes named in <meta-data android:name="com.brickssoft.locationtracking.LISTENER[.suffix]"> are created
|
|
26
|
+
# by reflection (Class.forName with the manifest name, then the public no-arg constructor). Keep the class names,
|
|
27
|
+
# that constructor and the listener methods of every implementation.
|
|
28
|
+
-keep class * implements com.brickssoft.locationtracking.api.LocationTrackingListener {
|
|
29
|
+
public <init>();
|
|
30
|
+
public void onRecord(android.content.Context, org.json.JSONObject);
|
|
31
|
+
public void onEvent(android.content.Context, java.lang.String, org.json.JSONObject);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Huawei HMS recommended keeps.
|
|
35
|
+
-keep class com.huawei.hms.** { *; }
|
|
36
|
+
-keep class com.huawei.hianalytics.** { *; }
|
|
37
|
+
-keep class com.huawei.updatesdk.** { *; }
|
|
38
|
+
-keepattributes *Annotation*
|
|
39
|
+
-keepattributes Exceptions
|
|
40
|
+
-keepattributes InnerClasses,EnclosingMethod
|
|
41
|
+
-keepattributes Signature
|
|
42
|
+
-keepattributes SourceFile,LineNumberTable
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
<uses-permission android:name="android.permission.INTERNET"/>
|
|
4
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
|
5
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
|
6
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
|
7
|
+
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
|
|
8
|
+
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
|
|
9
|
+
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" android:maxSdkVersion="28"/>
|
|
10
|
+
<uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" android:maxSdkVersion="28"/>
|
|
11
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
|
12
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
|
|
13
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
|
14
|
+
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
|
15
|
+
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
|
16
|
+
<!-- intentionally NOT declared: SCHEDULE_EXACT_ALARM, USE_EXACT_ALARM, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS -->
|
|
17
|
+
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
|
|
18
|
+
<queries>
|
|
19
|
+
<intent><action android:name="android.intent.action.SENDTO"/><data android:scheme="mailto"/></intent>
|
|
20
|
+
<package android:name="com.huawei.systemmanager"/><package android:name="com.hihonor.systemmanager"/>
|
|
21
|
+
<package android:name="com.miui.securitycenter"/><package android:name="com.miui.powerkeeper"/>
|
|
22
|
+
<package android:name="com.coloros.safecenter"/><package android:name="com.oppo.safe"/><package android:name="com.coloros.oppoguardelf"/>
|
|
23
|
+
<package android:name="com.iqoo.secure"/><package android:name="com.vivo.permissionmanager"/>
|
|
24
|
+
<package android:name="com.samsung.android.lool"/><package android:name="com.samsung.android.sm"/>
|
|
25
|
+
<package android:name="com.oneplus.security"/><package android:name="com.asus.mobilemanager"/>
|
|
26
|
+
<package android:name="com.letv.android.letvsafe"/><package android:name="com.htc.pitroad"/>
|
|
27
|
+
<package android:name="com.meizu.safe"/><package android:name="com.evenwell.powersaving.g3"/>
|
|
28
|
+
</queries>
|
|
29
|
+
<application>
|
|
30
|
+
<service android:name="com.brickssoft.locationtracking.service.LocationTrackingService"
|
|
31
|
+
android:exported="false" android:foregroundServiceType="location" android:stopWithTask="false"/>
|
|
32
|
+
<receiver android:name="com.brickssoft.locationtracking.service.BootReceiver" android:exported="true">
|
|
33
|
+
<intent-filter>
|
|
34
|
+
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
|
35
|
+
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
|
|
36
|
+
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
|
|
37
|
+
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
|
38
|
+
</intent-filter>
|
|
39
|
+
</receiver>
|
|
40
|
+
<receiver android:name="com.brickssoft.locationtracking.heartbeat.HeartbeatAlarmReceiver" android:exported="false"/>
|
|
41
|
+
<receiver android:name="com.brickssoft.locationtracking.service.NotificationActionReceiver" android:exported="false"/>
|
|
42
|
+
<receiver android:name="com.brickssoft.locationtracking.provider.gms.GmsActivityReceiver" android:exported="false"/>
|
|
43
|
+
<receiver android:name="com.brickssoft.locationtracking.provider.gms.GmsGeofenceReceiver" android:exported="false"/>
|
|
44
|
+
<receiver android:name="com.brickssoft.locationtracking.provider.hms.HmsActivityReceiver" android:exported="false"/>
|
|
45
|
+
<receiver android:name="com.brickssoft.locationtracking.provider.hms.HmsGeofenceReceiver" android:exported="false"/>
|
|
46
|
+
<receiver android:name="com.brickssoft.locationtracking.provider.android.AndroidGeofenceReceiver" android:exported="false"/>
|
|
47
|
+
<provider android:name="com.brickssoft.locationtracking.logging.LogFileProvider"
|
|
48
|
+
android:authorities="${applicationId}.locationtracking.logs" android:exported="false" android:grantUriPermissions="true">
|
|
49
|
+
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/lt_file_paths"/>
|
|
50
|
+
</provider>
|
|
51
|
+
</application>
|
|
52
|
+
</manifest>
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
package com.brickssoft.locationtracking
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import com.brickssoft.locationtracking.bridge.CallResponder
|
|
5
|
+
import com.brickssoft.locationtracking.bridge.CallWatchTarget
|
|
6
|
+
import com.brickssoft.locationtracking.bridge.ComponentServices
|
|
7
|
+
import com.brickssoft.locationtracking.bridge.PermissionRequestLauncher
|
|
8
|
+
import com.brickssoft.locationtracking.bridge.PluginHandlers
|
|
9
|
+
import com.brickssoft.locationtracking.bridge.PluginPermissionHost
|
|
10
|
+
import com.brickssoft.locationtracking.core.Components
|
|
11
|
+
import com.brickssoft.locationtracking.core.Logger
|
|
12
|
+
import com.brickssoft.locationtracking.core.Subscription
|
|
13
|
+
import com.brickssoft.locationtracking.permission.CurrentActivityTracker
|
|
14
|
+
import com.getcapacitor.JSObject
|
|
15
|
+
import com.getcapacitor.Plugin
|
|
16
|
+
import com.getcapacitor.PluginCall
|
|
17
|
+
import com.getcapacitor.PluginMethod
|
|
18
|
+
import com.getcapacitor.annotation.CapacitorPlugin
|
|
19
|
+
import com.getcapacitor.annotation.Permission
|
|
20
|
+
import com.getcapacitor.annotation.PermissionCallback
|
|
21
|
+
import kotlinx.coroutines.CancellationException
|
|
22
|
+
import kotlinx.coroutines.CoroutineStart
|
|
23
|
+
import kotlinx.coroutines.Job
|
|
24
|
+
import kotlinx.coroutines.isActive
|
|
25
|
+
import kotlinx.coroutines.launch
|
|
26
|
+
import org.json.JSONObject
|
|
27
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Capacitor bridge for `LocationTracking`. A thin adapter: every method runs the matching [PluginHandlers] function
|
|
31
|
+
* on `Components.scope` and settles the call (TrackingException -> `reject(message, code)`, anything else ->
|
|
32
|
+
* INTERNAL). Tracking events from the EventBus are forwarded to JS listeners.
|
|
33
|
+
*/
|
|
34
|
+
@CapacitorPlugin(
|
|
35
|
+
name = "LocationTracking",
|
|
36
|
+
permissions = [
|
|
37
|
+
Permission(
|
|
38
|
+
strings = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION],
|
|
39
|
+
alias = "location",
|
|
40
|
+
),
|
|
41
|
+
Permission(strings = [Manifest.permission.ACCESS_BACKGROUND_LOCATION], alias = "backgroundLocation"),
|
|
42
|
+
Permission(strings = [Manifest.permission.ACTIVITY_RECOGNITION], alias = "activityRecognition"),
|
|
43
|
+
Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "notifications"),
|
|
44
|
+
],
|
|
45
|
+
)
|
|
46
|
+
class LocationTrackingPlugin : Plugin() {
|
|
47
|
+
private lateinit var components: Components
|
|
48
|
+
private lateinit var handlers: PluginHandlers
|
|
49
|
+
|
|
50
|
+
@Volatile
|
|
51
|
+
private var eventSubscription: Subscription? = null
|
|
52
|
+
|
|
53
|
+
/** `onDone` of the in-flight permission request of each call, by callback id. */
|
|
54
|
+
private val pendingPermissionRequests = ConcurrentHashMap<String, () -> Unit>()
|
|
55
|
+
|
|
56
|
+
/** Running `requestPermissions` coroutines by callback id, cancelled in [handleOnDestroy]. */
|
|
57
|
+
private val permissionJobs = ConcurrentHashMap<String, Job>()
|
|
58
|
+
|
|
59
|
+
@Volatile
|
|
60
|
+
private var destroyed = false
|
|
61
|
+
|
|
62
|
+
override fun load() {
|
|
63
|
+
components = Components.get(context)
|
|
64
|
+
// The Activity is already created when plugins load, so the permission manager's lifecycle tracker would
|
|
65
|
+
// only learn about it at its next lifecycle event; seed it for rationale checks in checkPermissions().
|
|
66
|
+
activity?.let { CurrentActivityTracker.attach(context).remember(it) }
|
|
67
|
+
handlers = PluginHandlers(
|
|
68
|
+
ComponentServices(components),
|
|
69
|
+
activityProvider = { PluginPermissionHost.usableActivity(this) },
|
|
70
|
+
)
|
|
71
|
+
eventSubscription = handlers.forwardEvents { name, payload -> notifyOnBridgeThread(name, payload) }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
override fun handleOnResume() {
|
|
75
|
+
super.handleOnResume()
|
|
76
|
+
if (!::handlers.isInitialized) return
|
|
77
|
+
components.scope.launch { handlers.onResume() }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Stops event forwarding, releases every watch and ends in-flight permission requests: their calls are
|
|
82
|
+
* abandoned (the WebView is going away), but each pending `onDone` still runs so the PermissionManager's request
|
|
83
|
+
* completes; later steps of it complete at once because the host has no usable activity and no launcher.
|
|
84
|
+
*/
|
|
85
|
+
override fun handleOnDestroy() {
|
|
86
|
+
destroyed = true
|
|
87
|
+
eventSubscription?.cancel()
|
|
88
|
+
eventSubscription = null
|
|
89
|
+
if (::handlers.isInitialized) handlers.releaseAllWatches()
|
|
90
|
+
for (id in pendingPermissionRequests.keys.toList()) {
|
|
91
|
+
val onDone = pendingPermissionRequests.remove(id) ?: continue
|
|
92
|
+
try {
|
|
93
|
+
onDone()
|
|
94
|
+
} catch (t: Throwable) {
|
|
95
|
+
Logger.w(TAG, "completing permission request $id on destroy failed", t)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
permissionJobs.values.forEach { it.cancel() }
|
|
99
|
+
permissionJobs.clear()
|
|
100
|
+
super.handleOnDestroy()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---- lifecycle and config
|
|
104
|
+
|
|
105
|
+
@PluginMethod
|
|
106
|
+
fun ready(call: PluginCall) {
|
|
107
|
+
respond(call) { handlers.ready(it) }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@PluginMethod
|
|
111
|
+
fun setConfig(call: PluginCall) {
|
|
112
|
+
respond(call) { handlers.setConfig(it) }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@PluginMethod
|
|
116
|
+
fun reset(call: PluginCall) {
|
|
117
|
+
respond(call) { handlers.reset(it) }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@PluginMethod
|
|
121
|
+
fun getState(call: PluginCall) {
|
|
122
|
+
respond(call) { handlers.getState() }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@PluginMethod
|
|
126
|
+
fun start(call: PluginCall) {
|
|
127
|
+
respond(call) { handlers.start() }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@PluginMethod
|
|
131
|
+
fun startGeofences(call: PluginCall) {
|
|
132
|
+
respond(call) { handlers.startGeofences() }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@PluginMethod
|
|
136
|
+
fun stop(call: PluginCall) {
|
|
137
|
+
respond(call) { handlers.stop() }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@PluginMethod
|
|
141
|
+
fun changePace(call: PluginCall) {
|
|
142
|
+
respond(call) { handlers.changePace(it) }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ---- positions
|
|
146
|
+
|
|
147
|
+
@PluginMethod
|
|
148
|
+
fun getCurrentPosition(call: PluginCall) {
|
|
149
|
+
respond(call) { handlers.getCurrentPosition(it) }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Kept alive until `clearWatch`: the bridge saves the call and every location/error invokes the JS callback.
|
|
154
|
+
* Kept alive before registering so an early delivery cannot release the call.
|
|
155
|
+
*/
|
|
156
|
+
@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
|
|
157
|
+
fun watchPosition(call: PluginCall) {
|
|
158
|
+
call.setKeepAlive(true)
|
|
159
|
+
try {
|
|
160
|
+
handlers.watchPosition(call.callbackId, optionsOf(call), CallWatchTarget(call) { bridge })
|
|
161
|
+
} catch (t: Throwable) { // also Errors (e.g. NoClassDefFoundError of a missing SDK): never crash the bridge
|
|
162
|
+
call.setKeepAlive(false)
|
|
163
|
+
CallResponder.reject(call, t)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@PluginMethod
|
|
168
|
+
fun clearWatch(call: PluginCall) {
|
|
169
|
+
respond(call) { handlers.clearWatch(it) }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ---- odometer
|
|
173
|
+
|
|
174
|
+
@PluginMethod
|
|
175
|
+
fun getOdometer(call: PluginCall) {
|
|
176
|
+
respond(call) { handlers.getOdometer() }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@PluginMethod
|
|
180
|
+
fun setOdometer(call: PluginCall) {
|
|
181
|
+
respond(call) { handlers.setOdometer(it) }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@PluginMethod
|
|
185
|
+
fun resetOdometer(call: PluginCall) {
|
|
186
|
+
respond(call) { handlers.resetOdometer() }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ---- records
|
|
190
|
+
|
|
191
|
+
@PluginMethod
|
|
192
|
+
fun getLocations(call: PluginCall) {
|
|
193
|
+
respond(call) { handlers.getLocations(it) }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@PluginMethod
|
|
197
|
+
fun getCount(call: PluginCall) {
|
|
198
|
+
respond(call) { handlers.getCount() }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@PluginMethod
|
|
202
|
+
fun insertLocation(call: PluginCall) {
|
|
203
|
+
respond(call) { handlers.insertLocation(it) }
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@PluginMethod
|
|
207
|
+
fun destroyLocations(call: PluginCall) {
|
|
208
|
+
respond(call) { handlers.destroyLocations() }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@PluginMethod
|
|
212
|
+
fun destroyLocation(call: PluginCall) {
|
|
213
|
+
respond(call) { handlers.destroyLocation(it) }
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@PluginMethod
|
|
217
|
+
fun sync(call: PluginCall) {
|
|
218
|
+
respond(call) { handlers.sync() }
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ---- geofences
|
|
222
|
+
|
|
223
|
+
@PluginMethod
|
|
224
|
+
fun addGeofence(call: PluginCall) {
|
|
225
|
+
respond(call) { handlers.addGeofence(it) }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@PluginMethod
|
|
229
|
+
fun addGeofences(call: PluginCall) {
|
|
230
|
+
respond(call) { handlers.addGeofences(it) }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@PluginMethod
|
|
234
|
+
fun removeGeofence(call: PluginCall) {
|
|
235
|
+
respond(call) { handlers.removeGeofence(it) }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@PluginMethod
|
|
239
|
+
fun removeGeofences(call: PluginCall) {
|
|
240
|
+
respond(call) { handlers.removeGeofences(it) }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@PluginMethod
|
|
244
|
+
fun getGeofences(call: PluginCall) {
|
|
245
|
+
respond(call) { handlers.getGeofences() }
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@PluginMethod
|
|
249
|
+
fun getGeofence(call: PluginCall) {
|
|
250
|
+
respond(call) { handlers.getGeofence(it) }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
@PluginMethod
|
|
254
|
+
fun geofenceExists(call: PluginCall) {
|
|
255
|
+
respond(call) { handlers.geofenceExists(it) }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ---- heartbeat and device
|
|
259
|
+
|
|
260
|
+
@PluginMethod
|
|
261
|
+
fun getHeartbeatStatus(call: PluginCall) {
|
|
262
|
+
respond(call) { handlers.getHeartbeatStatus() }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@PluginMethod
|
|
266
|
+
fun getProviderState(call: PluginCall) {
|
|
267
|
+
respond(call) { handlers.getProviderState() }
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@PluginMethod
|
|
271
|
+
fun isPowerSaveMode(call: PluginCall) {
|
|
272
|
+
respond(call) { handlers.isPowerSaveMode() }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@PluginMethod
|
|
276
|
+
fun getBatteryOptimizationStatus(call: PluginCall) {
|
|
277
|
+
respond(call) { handlers.getBatteryOptimizationStatus() }
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
@PluginMethod
|
|
281
|
+
fun openBatteryOptimizationSettings(call: PluginCall) {
|
|
282
|
+
respond(call) { handlers.openBatteryOptimizationSettings() }
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
@PluginMethod
|
|
286
|
+
fun getPowerManagerInfo(call: PluginCall) {
|
|
287
|
+
respond(call) { handlers.getPowerManagerInfo() }
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
@PluginMethod
|
|
291
|
+
fun openPowerManagerSettings(call: PluginCall) {
|
|
292
|
+
respond(call) { handlers.openPowerManagerSettings() }
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
@PluginMethod
|
|
296
|
+
fun openLocationSettings(call: PluginCall) {
|
|
297
|
+
respond(call) { handlers.openLocationSettings() }
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
@PluginMethod
|
|
301
|
+
fun openAppSettings(call: PluginCall) {
|
|
302
|
+
respond(call) { handlers.openAppSettings() }
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
@PluginMethod
|
|
306
|
+
fun getDeviceInfo(call: PluginCall) {
|
|
307
|
+
respond(call) { handlers.getDeviceInfo() }
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@PluginMethod
|
|
311
|
+
fun getSensors(call: PluginCall) {
|
|
312
|
+
respond(call) { handlers.getSensors() }
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ---- permissions
|
|
316
|
+
|
|
317
|
+
@PluginMethod
|
|
318
|
+
override fun checkPermissions(call: PluginCall) {
|
|
319
|
+
respond(call) { handlers.checkPermissions() }
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@PluginMethod
|
|
323
|
+
override fun requestPermissions(call: PluginCall) {
|
|
324
|
+
val id = call.callbackId
|
|
325
|
+
val host = PluginPermissionHost(
|
|
326
|
+
this,
|
|
327
|
+
launcher = PermissionRequestLauncher { aliases, onDone -> launchPermissionRequest(call, aliases, onDone) },
|
|
328
|
+
)
|
|
329
|
+
val job = respond(call, CoroutineStart.LAZY) { handlers.requestPermissions(it, host) }
|
|
330
|
+
permissionJobs[id] = job
|
|
331
|
+
job.invokeOnCompletion {
|
|
332
|
+
permissionJobs.remove(id, job)
|
|
333
|
+
pendingPermissionRequests.remove(id)
|
|
334
|
+
}
|
|
335
|
+
job.start()
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Main thread (called by the PermissionManager through [PluginPermissionHost]). */
|
|
339
|
+
private fun launchPermissionRequest(call: PluginCall, aliases: List<String>, onDone: () -> Unit) {
|
|
340
|
+
if (destroyed) {
|
|
341
|
+
onDone()
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
val id = call.callbackId
|
|
345
|
+
pendingPermissionRequests[id] = onDone
|
|
346
|
+
try {
|
|
347
|
+
requestPermissionForAliases(aliases.toTypedArray(), call, PERMISSION_CALLBACK)
|
|
348
|
+
} catch (e: Exception) {
|
|
349
|
+
pendingPermissionRequests.remove(id)
|
|
350
|
+
throw e
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** Resolved by name ([PERMISSION_CALLBACK]) through reflection by Capacitor; main thread. */
|
|
355
|
+
@Suppress("unused")
|
|
356
|
+
@PermissionCallback
|
|
357
|
+
private fun onPermissionRequestResult(call: PluginCall?) {
|
|
358
|
+
val id = call?.callbackId ?: return
|
|
359
|
+
val onDone = pendingPermissionRequests.remove(id) ?: return
|
|
360
|
+
onDone()
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ---- log
|
|
364
|
+
|
|
365
|
+
@PluginMethod
|
|
366
|
+
fun log(call: PluginCall) {
|
|
367
|
+
respond(call) { handlers.log(it) }
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
@PluginMethod
|
|
371
|
+
fun getLog(call: PluginCall) {
|
|
372
|
+
respond(call) { handlers.getLog(it) }
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@PluginMethod
|
|
376
|
+
fun destroyLog(call: PluginCall) {
|
|
377
|
+
respond(call) { handlers.destroyLog() }
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@PluginMethod
|
|
381
|
+
fun uploadLog(call: PluginCall) {
|
|
382
|
+
respond(call) { handlers.uploadLog(it) }
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
@PluginMethod
|
|
386
|
+
fun emailLog(call: PluginCall) {
|
|
387
|
+
respond(call) { handlers.emailLog(it) }
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ---- plumbing
|
|
391
|
+
|
|
392
|
+
/** Runs [block] on `Components.scope` and settles [call] with its result (null = void) or error. */
|
|
393
|
+
private fun respond(
|
|
394
|
+
call: PluginCall,
|
|
395
|
+
start: CoroutineStart = CoroutineStart.DEFAULT,
|
|
396
|
+
block: suspend (JSONObject) -> JSONObject?,
|
|
397
|
+
): Job = components.scope.launch(start = start) {
|
|
398
|
+
try {
|
|
399
|
+
CallResponder.resolve(call, block(optionsOf(call)))
|
|
400
|
+
} catch (t: Throwable) { // also Errors (e.g. NoClassDefFoundError of a missing SDK): always settle the call
|
|
401
|
+
// Our own cancellation (plugin destroyed / scope cancelled): nobody is listening any more.
|
|
402
|
+
if (t is CancellationException && !isActive) return@launch
|
|
403
|
+
CallResponder.reject(call, t)
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Emits on the bridge's plugin thread, where Capacitor also adds and removes listeners, so the listener list is
|
|
409
|
+
* never read and modified concurrently. The payload is built only if JS listens; events are dropped while no
|
|
410
|
+
* bridge is attached.
|
|
411
|
+
*/
|
|
412
|
+
private fun notifyOnBridgeThread(name: String, payload: () -> JSONObject) {
|
|
413
|
+
val b = bridge ?: return
|
|
414
|
+
b.execute {
|
|
415
|
+
try {
|
|
416
|
+
if (hasListeners(name)) notifyListeners(name, JSObject.fromJSONObject(payload()))
|
|
417
|
+
} catch (t: Throwable) {
|
|
418
|
+
Logger.e(TAG, "notifyListeners($name) failed", t)
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
private fun optionsOf(call: PluginCall): JSONObject = call.data ?: JSObject()
|
|
424
|
+
|
|
425
|
+
private companion object {
|
|
426
|
+
const val TAG = "LT.Plugin"
|
|
427
|
+
|
|
428
|
+
/** Name of the `@PermissionCallback` method; Capacitor looks it up by name. */
|
|
429
|
+
const val PERMISSION_CALLBACK = "onPermissionRequestResult"
|
|
430
|
+
}
|
|
431
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// CONTRACT (scaffold, round 2): signatures fixed by docs/e2e/architecture.md §2. Owned by Unit 5 (Companion native
|
|
2
|
+
// API) for KDoc and behavior only; do not change the signatures.
|
|
3
|
+
package com.brickssoft.locationtracking.api
|
|
4
|
+
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import org.json.JSONObject
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Receives every queued record and every tracking event natively, also in processes where no WebView (and no JS)
|
|
10
|
+
* exists: after a reboot, a heartbeat alarm or a `START_STICKY` restart.
|
|
11
|
+
*
|
|
12
|
+
* Register it in one of two ways:
|
|
13
|
+
* - **Manifest** (recommended for a companion plugin that must never miss an event): a `<meta-data>` inside
|
|
14
|
+
* `<application>` whose name is [LocationTrackingNative.LISTENER_META_DATA] (or starts with it followed by `.`, for
|
|
15
|
+
* a second listener) and whose value is the fully qualified class name. The class needs a public no-arg
|
|
16
|
+
* constructor. It is instantiated once per process in `Components.bootstrap()`, which every entry point runs
|
|
17
|
+
* (plugin load, service, receivers) before the engine can emit anything.
|
|
18
|
+
* - **Programmatically**: [LocationTrackingNative.addListener]; receives only what is emitted after the call.
|
|
19
|
+
*
|
|
20
|
+
* Methods run on the plugin's single `LT-native` background thread, in emission order (a record's [onRecord] comes
|
|
21
|
+
* before the events that carry it). Every exception (also an Error) thrown by a method is caught and logged, and the
|
|
22
|
+
* other listeners still receive the call. Delivery never blocks the engine, but one slow listener delays every later
|
|
23
|
+
* delivery to every listener: keep the methods short and hand long work (I/O, uploads) to your own executor.
|
|
24
|
+
*
|
|
25
|
+
* Both methods receive the application context and a JSONObject built for this listener alone (changing it does not
|
|
26
|
+
* affect other listeners). Guide: `docs/native-api.md`.
|
|
27
|
+
*/
|
|
28
|
+
interface LocationTrackingListener {
|
|
29
|
+
/**
|
|
30
|
+
* Every record queued for upload, including `tracking_start`/`tracking_stop`, `providerchange`, `heartbeat`,
|
|
31
|
+
* `geofence` and `insertLocation()` records: the wire JSON of `RecordJson.toJson(record)` (no `sent_at`). A record
|
|
32
|
+
* the plugin creates is delivered also when the plugin failed to store it in its database; an `insertLocation()`
|
|
33
|
+
* whose insert fails is rejected instead and not delivered.
|
|
34
|
+
*/
|
|
35
|
+
fun onRecord(context: Context, record: JSONObject) {}
|
|
36
|
+
|
|
37
|
+
/** Every JS event, with the same name and payload as the JS `addListener` API (`EventJson.name` / `payload`). */
|
|
38
|
+
fun onEvent(context: Context, name: String, payload: JSONObject) {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Returned by [LocationTrackingNative.addListener]. Idempotent. */
|
|
42
|
+
fun interface NativeSubscription {
|
|
43
|
+
fun remove()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Result of a [LocationTrackingNative] call, always invoked on the `LT-native` thread. A failure carries a
|
|
48
|
+
* `com.brickssoft.locationtracking.core.TrackingException` whose `code` is the JS `ErrorCode`.
|
|
49
|
+
*/
|
|
50
|
+
fun interface NativeCallback<T> {
|
|
51
|
+
fun onResult(result: Result<T>)
|
|
52
|
+
}
|