init
This commit is contained in:
72
node_modules/@capacitor/geolocation/android/build.gradle
generated
vendored
Normal file
72
node_modules/@capacitor/geolocation/android/build.gradle
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
ext {
|
||||
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
||||
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
|
||||
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
|
||||
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
|
||||
playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '21.3.0'
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.9.25'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.7.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
namespace "com.capacitorjs.plugins.geolocation"
|
||||
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
|
||||
defaultConfig {
|
||||
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
||||
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(21)
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation("io.ionic.libs:iongeolocation-android:1.0.0")
|
||||
implementation project(':capacitor-android')
|
||||
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4")
|
||||
implementation "com.google.android.gms:play-services-location:$playServicesLocationVersion"
|
||||
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||
}
|
||||
2
node_modules/@capacitor/geolocation/android/src/main/AndroidManifest.xml
generated
vendored
Normal file
2
node_modules/@capacitor/geolocation/android/src/main/AndroidManifest.xml
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
</manifest>
|
||||
71
node_modules/@capacitor/geolocation/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationErrors.kt
generated
vendored
Normal file
71
node_modules/@capacitor/geolocation/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationErrors.kt
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package com.capacitorjs.plugins.geolocation
|
||||
|
||||
/**
|
||||
* Object with plugin errors
|
||||
*/
|
||||
object GeolocationErrors {
|
||||
|
||||
private fun formatErrorCode(number: Int): String {
|
||||
return "OS-PLUG-GLOC-" + number.toString().padStart(4, '0')
|
||||
}
|
||||
|
||||
data class ErrorInfo(
|
||||
val code: String,
|
||||
val message: String
|
||||
)
|
||||
|
||||
val POSITION_UNAVAILABLE = ErrorInfo(
|
||||
code = formatErrorCode(2),
|
||||
message = "There was en error trying to obtain the location."
|
||||
)
|
||||
|
||||
val LOCATION_PERMISSIONS_DENIED = ErrorInfo(
|
||||
code = formatErrorCode(3),
|
||||
message = "Location permission request was denied."
|
||||
)
|
||||
|
||||
val LOCATION_DISABLED = ErrorInfo(
|
||||
code = formatErrorCode(7),
|
||||
message = "Location services are not enabled."
|
||||
)
|
||||
|
||||
val LOCATION_ENABLE_REQUEST_DENIED = ErrorInfo(
|
||||
code = formatErrorCode(9),
|
||||
message = "Request to enable location was denied."
|
||||
)
|
||||
|
||||
val GET_LOCATION_TIMEOUT = ErrorInfo(
|
||||
code = formatErrorCode(10),
|
||||
message = "Could not obtain location in time. Try with a higher timeout."
|
||||
)
|
||||
|
||||
val INVALID_TIMEOUT = ErrorInfo(
|
||||
code = formatErrorCode(11),
|
||||
message = "Timeout needs to be a positive value."
|
||||
)
|
||||
|
||||
val WATCH_ID_NOT_FOUND = ErrorInfo(
|
||||
code = formatErrorCode(12),
|
||||
message = "WatchId not found."
|
||||
)
|
||||
|
||||
val WATCH_ID_NOT_PROVIDED = ErrorInfo(
|
||||
code = formatErrorCode(13),
|
||||
message = "WatchId needs to be provided."
|
||||
)
|
||||
|
||||
val GOOGLE_SERVICES_RESOLVABLE = ErrorInfo(
|
||||
code = formatErrorCode(14),
|
||||
message = "Google Play Services error user resolvable."
|
||||
)
|
||||
|
||||
val GOOGLE_SERVICES_ERROR = ErrorInfo(
|
||||
code = formatErrorCode(15),
|
||||
message = "Google Play Services error."
|
||||
)
|
||||
|
||||
val LOCATION_SETTINGS_ERROR = ErrorInfo(
|
||||
code = formatErrorCode(16),
|
||||
message = "Location settings error."
|
||||
)
|
||||
}
|
||||
341
node_modules/@capacitor/geolocation/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt
generated
vendored
Normal file
341
node_modules/@capacitor/geolocation/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
package com.capacitorjs.plugins.geolocation
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import com.getcapacitor.JSObject
|
||||
import com.getcapacitor.PermissionState
|
||||
import com.getcapacitor.Plugin
|
||||
import com.getcapacitor.PluginCall
|
||||
import com.getcapacitor.PluginMethod
|
||||
import com.getcapacitor.annotation.CapacitorPlugin
|
||||
import com.getcapacitor.annotation.Permission
|
||||
import com.getcapacitor.annotation.PermissionCallback
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import io.ionic.libs.iongeolocationlib.controller.IONGLOCController
|
||||
import io.ionic.libs.iongeolocationlib.model.IONGLOCException
|
||||
import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationOptions
|
||||
import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationResult
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@CapacitorPlugin(
|
||||
name = "Geolocation",
|
||||
permissions = [Permission(
|
||||
strings = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION],
|
||||
alias = GeolocationPlugin.LOCATION_ALIAS
|
||||
), Permission(
|
||||
strings = [Manifest.permission.ACCESS_COARSE_LOCATION],
|
||||
alias = GeolocationPlugin.COARSE_LOCATION_ALIAS
|
||||
)]
|
||||
)
|
||||
class GeolocationPlugin : Plugin() {
|
||||
|
||||
private lateinit var controller: IONGLOCController
|
||||
private lateinit var coroutineScope: CoroutineScope
|
||||
private val watchingCalls: MutableMap<String, PluginCall> = mutableMapOf()
|
||||
|
||||
companion object {
|
||||
const val LOCATION_ALIAS: String = "location"
|
||||
const val COARSE_LOCATION_ALIAS: String = "coarseLocation"
|
||||
}
|
||||
|
||||
override fun load() {
|
||||
super.load()
|
||||
|
||||
coroutineScope = CoroutineScope(Dispatchers.Main)
|
||||
val activityLauncher = activity.registerForActivityResult(
|
||||
ActivityResultContracts.StartIntentSenderForResult()
|
||||
) { result ->
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
controller.onResolvableExceptionResult(result.resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
this.controller = IONGLOCController(
|
||||
LocationServices.getFusedLocationProviderClient(context),
|
||||
activityLauncher
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
override fun handleOnDestroy() {
|
||||
super.handleOnDestroy()
|
||||
coroutineScope.cancel()
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
override fun checkPermissions(call: PluginCall) {
|
||||
checkLocationState(call) { super.checkPermissions(call) }
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
override fun requestPermissions(call: PluginCall) {
|
||||
checkLocationState(call) { super.requestPermissions(call) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine if location services are enabled or not
|
||||
* @param call the PluginCall to use in case we want to send an error
|
||||
* @param onLocationEnabled lambda function to use in case location services are enabled
|
||||
*/
|
||||
private fun checkLocationState(call: PluginCall, onLocationEnabled: () -> Unit) {
|
||||
if (controller.areLocationServicesEnabled(context)) {
|
||||
onLocationEnabled()
|
||||
} else {
|
||||
call.sendError(GeolocationErrors.LOCATION_DISABLED)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks location permission state, requesting them if necessary.
|
||||
* If not, calls getPosition to get the device's position
|
||||
* @param call the plugin call
|
||||
*/
|
||||
@PluginMethod
|
||||
fun getCurrentPosition(call: PluginCall) {
|
||||
handlePermissionRequest(call, "completeCurrentPosition") { getPosition(call) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks location permission state, requesting them if necessary.
|
||||
* If not, calls startWatch to start getting location updates
|
||||
* @param call the plugin call
|
||||
*/
|
||||
@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
|
||||
fun watchPosition(call: PluginCall) {
|
||||
handlePermissionRequest(call, "completeWatchPosition") { startWatch(call) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine if a permission is granted or not and request it if necessary
|
||||
* @param call the PluginCall to use in case we want to send an error
|
||||
* @param callbackName a string identifying the callback to call once the permission prompt is answered
|
||||
* @param onPermissionGranted lambda function to use in case the permission is enabled
|
||||
*/
|
||||
private fun handlePermissionRequest(
|
||||
call: PluginCall,
|
||||
callbackName: String,
|
||||
onPermissionGranted: () -> Unit
|
||||
) {
|
||||
val alias = getAlias(call)
|
||||
if (getPermissionState(alias) != PermissionState.GRANTED) {
|
||||
requestPermissionForAlias(alias, call, callbackName)
|
||||
} else {
|
||||
onPermissionGranted()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the getCurrentPosition plugin call after a permission request
|
||||
* @see .getCurrentPosition
|
||||
* @param call the plugin call
|
||||
*/
|
||||
@PermissionCallback
|
||||
private fun completeCurrentPosition(call: PluginCall) {
|
||||
handlePermissionResult(call) { getPosition(call) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the watchPosition plugin call after a permission request
|
||||
* @see .startWatch
|
||||
* @param call the plugin call
|
||||
*/
|
||||
@PermissionCallback
|
||||
private fun completeWatchPosition(call: PluginCall) {
|
||||
handlePermissionResult(call) { startWatch(call) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to handle the result of a location permission request
|
||||
* @param call the PluginCall to use in case we want to send an error
|
||||
* @param onPermissionGranted lambda function to use in case the permission was granted
|
||||
*/
|
||||
private fun handlePermissionResult(call: PluginCall, onPermissionGranted: () -> Unit) {
|
||||
if (getPermissionState(COARSE_LOCATION_ALIAS) == PermissionState.GRANTED) {
|
||||
onPermissionGranted()
|
||||
} else {
|
||||
call.sendError(GeolocationErrors.LOCATION_PERMISSIONS_DENIED)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the watch, removing location updates.
|
||||
* @param call the plugin call
|
||||
*/
|
||||
@PluginMethod
|
||||
fun clearWatch(call: PluginCall) {
|
||||
val id = call.getString("id")
|
||||
if (id.isNullOrBlank()) {
|
||||
call.sendError(GeolocationErrors.WATCH_ID_NOT_PROVIDED)
|
||||
} else {
|
||||
watchingCalls.remove(id)?.release(bridge)
|
||||
val watchCleared = controller.clearWatch(id)
|
||||
if (watchCleared) {
|
||||
call.sendSuccess()
|
||||
} else {
|
||||
call.sendError(GeolocationErrors.WATCH_ID_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate permission alias
|
||||
* @param call the plugin call
|
||||
* @return String with correct alias
|
||||
*/
|
||||
private fun getAlias(call: PluginCall): String {
|
||||
var alias = LOCATION_ALIAS
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val enableHighAccuracy = call.getBoolean("enableHighAccuracy") ?: false
|
||||
if (!enableHighAccuracy) {
|
||||
alias = COARSE_LOCATION_ALIAS
|
||||
}
|
||||
}
|
||||
return alias
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current position
|
||||
* @param call the plugin call
|
||||
*/
|
||||
private fun getPosition(call: PluginCall) {
|
||||
coroutineScope.launch {
|
||||
val locationOptions = createOptions(call)
|
||||
|
||||
// call getCurrentPosition method from controller
|
||||
val locationResult = controller.getCurrentPosition(activity, locationOptions)
|
||||
|
||||
locationResult
|
||||
.onSuccess { location ->
|
||||
call.sendSuccess(getJSObjectForLocation(location))
|
||||
}
|
||||
.onFailure { exception ->
|
||||
onLocationError(exception, call)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts watching the device's location by requesting location updates
|
||||
* @param call the plugin call
|
||||
*/
|
||||
private fun startWatch(call: PluginCall) {
|
||||
coroutineScope.launch {
|
||||
val watchId = call.callbackId
|
||||
|
||||
val locationOptions = createOptions(call)
|
||||
|
||||
// call addWatch method from controller
|
||||
controller.addWatch(activity, locationOptions, watchId).collect { result ->
|
||||
result.onSuccess { locationList ->
|
||||
locationList.forEach { locationResult ->
|
||||
call.sendSuccess(
|
||||
result = getJSObjectForLocation(locationResult),
|
||||
keepCallback = true)
|
||||
}
|
||||
}
|
||||
result.onFailure { exception ->
|
||||
onLocationError(exception, call)
|
||||
}
|
||||
}
|
||||
}
|
||||
watchingCalls[call.callbackId] = call
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert IONGLOCLocationResult object into the format accepted by the Capacitor bridge
|
||||
* @param locationResult IONGLOCLocationResult object with the location to convert
|
||||
* @return JSObject with converted JSON object
|
||||
*/
|
||||
private fun getJSObjectForLocation(locationResult: IONGLOCLocationResult): JSObject {
|
||||
val coords = JSObject().apply {
|
||||
put("latitude", locationResult.latitude)
|
||||
put("longitude", locationResult.longitude)
|
||||
put("accuracy", locationResult.accuracy)
|
||||
put("altitude", locationResult.altitude)
|
||||
locationResult.altitudeAccuracy?.let { put("altitudeAccuracy", it) }
|
||||
put("speed", locationResult.speed)
|
||||
put("heading", locationResult.heading)
|
||||
}
|
||||
return JSObject().apply {
|
||||
put("timestamp", locationResult.timestamp)
|
||||
put("coords", coords)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to handle error cases
|
||||
* @param exception Throwable to handle as an error
|
||||
* @param call the plugin call
|
||||
*/
|
||||
private fun onLocationError(exception: Throwable?, call: PluginCall) {
|
||||
when (exception) {
|
||||
is IONGLOCException.IONGLOCRequestDeniedException -> {
|
||||
call.sendError(GeolocationErrors.LOCATION_ENABLE_REQUEST_DENIED)
|
||||
}
|
||||
is IONGLOCException.IONGLOCSettingsException -> {
|
||||
call.sendError(GeolocationErrors.LOCATION_SETTINGS_ERROR)
|
||||
}
|
||||
is IONGLOCException.IONGLOCInvalidTimeoutException -> {
|
||||
call.sendError(GeolocationErrors.INVALID_TIMEOUT)
|
||||
}
|
||||
is IONGLOCException.IONGLOCGoogleServicesException -> {
|
||||
if (exception.resolvable) {
|
||||
call.sendError(GeolocationErrors.GOOGLE_SERVICES_RESOLVABLE)
|
||||
} else {
|
||||
call.sendError(GeolocationErrors.GOOGLE_SERVICES_ERROR)
|
||||
}
|
||||
}
|
||||
is IONGLOCException.IONGLOCLocationRetrievalTimeoutException -> {
|
||||
call.sendError(GeolocationErrors.GET_LOCATION_TIMEOUT)
|
||||
}
|
||||
else -> {
|
||||
call.sendError(GeolocationErrors.POSITION_UNAVAILABLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension function to return a successful plugin result
|
||||
* @param result JSOObject with the JSON content to return
|
||||
* @param keepCallback boolean to determine if callback should be kept for future calls or not
|
||||
*/
|
||||
private fun PluginCall.sendSuccess(result: JSObject? = null, keepCallback: Boolean? = false) {
|
||||
this.setKeepAlive(keepCallback)
|
||||
if (result != null) {
|
||||
this.resolve(result)
|
||||
} else {
|
||||
this.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension function to return a unsuccessful plugin result
|
||||
* @param error error class representing the error to return, containing a code and message
|
||||
*/
|
||||
private fun PluginCall.sendError(error: GeolocationErrors.ErrorInfo) {
|
||||
this.reject(error.message, error.code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the location options to pass to the native controller
|
||||
* @param call the plugin call
|
||||
* @return IONGLOCLocationOptions object
|
||||
*/
|
||||
private fun createOptions(call: PluginCall): IONGLOCLocationOptions {
|
||||
val timeout = call.getNumber("timeout", 10000)
|
||||
val maximumAge = call.getNumber("maximumAge", 0)
|
||||
val enableHighAccuracy = call.getBoolean("enableHighAccuracy", false) ?: false
|
||||
val minimumUpdateInterval = call.getNumber("minimumUpdateInterval", 5000)
|
||||
|
||||
val locationOptions = IONGLOCLocationOptions(timeout, maximumAge, enableHighAccuracy, minimumUpdateInterval)
|
||||
|
||||
return locationOptions
|
||||
}
|
||||
|
||||
private fun PluginCall.getNumber(name: String, defaultValue: Long): Long =
|
||||
getLong(name) ?: getInt(name)?.toLong() ?: defaultValue
|
||||
}
|
||||
0
node_modules/@capacitor/geolocation/android/src/main/res/.gitkeep
generated
vendored
Normal file
0
node_modules/@capacitor/geolocation/android/src/main/res/.gitkeep
generated
vendored
Normal file
Reference in New Issue
Block a user