-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #28 from hotwired/location-access
Location access via JavaScript
- Loading branch information
Showing
10 changed files
with
211 additions
and
8 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
core/src/main/kotlin/dev/hotwire/core/files/delegates/GeolocationPermissionDelegate.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package dev.hotwire.core.files.delegates | ||
|
||
import android.Manifest.permission.ACCESS_COARSE_LOCATION | ||
import android.Manifest.permission.ACCESS_FINE_LOCATION | ||
import android.content.Context | ||
import android.content.pm.PackageManager | ||
import android.os.Build | ||
import android.webkit.GeolocationPermissions | ||
import androidx.core.content.ContextCompat | ||
import androidx.core.content.PermissionChecker | ||
import dev.hotwire.core.files.util.HOTWIRE_REQUEST_CODE_GEOLOCATION_PERMISSION | ||
import dev.hotwire.core.logging.logError | ||
import dev.hotwire.core.turbo.session.Session | ||
|
||
class GeolocationPermissionDelegate(private val session: Session) { | ||
private val context: Context = session.context | ||
private val permissionToRequest = preferredLocationPermission() | ||
|
||
private var requestOrigin: String? = null | ||
private var requestCallback: GeolocationPermissions.Callback? = null | ||
|
||
fun onRequestPermission( | ||
origin: String?, | ||
callback: GeolocationPermissions.Callback? | ||
) { | ||
requestOrigin = origin | ||
requestCallback = callback | ||
|
||
if (requestOrigin == null || requestCallback == null || permissionToRequest == null) { | ||
permissionDenied() | ||
} else if (hasLocationPermission(context)) { | ||
permissionGranted() | ||
} else { | ||
startPermissionRequest() | ||
} | ||
} | ||
|
||
fun onActivityResult(isGranted: Boolean) { | ||
if (isGranted) { | ||
permissionGranted() | ||
} else { | ||
permissionDenied() | ||
} | ||
} | ||
|
||
private fun startPermissionRequest() { | ||
val destination = session.currentVisit?.callback?.visitDestination() ?: return | ||
val resultLauncher = destination.activityPermissionResultLauncher( | ||
HOTWIRE_REQUEST_CODE_GEOLOCATION_PERMISSION | ||
) | ||
|
||
try { | ||
resultLauncher?.launch(permissionToRequest) | ||
} catch (e: Exception) { | ||
logError("startGeolocationPermissionError", e) | ||
permissionDenied() | ||
} | ||
} | ||
|
||
private fun hasLocationPermission(context: Context): Boolean { | ||
return permissionToRequest?.let { | ||
ContextCompat.checkSelfPermission(context, it) == PermissionChecker.PERMISSION_GRANTED | ||
} == true | ||
} | ||
|
||
private fun permissionGranted() { | ||
requestCallback?.invoke(requestOrigin, true, true) | ||
requestOrigin = null | ||
requestCallback = null | ||
} | ||
|
||
private fun permissionDenied() { | ||
requestCallback?.invoke(requestOrigin, false, false) | ||
requestOrigin = null | ||
requestCallback = null | ||
} | ||
|
||
private fun preferredLocationPermission(): String? { | ||
val declaredPermissions = manifestPermissions().filter { | ||
it == ACCESS_COARSE_LOCATION || | ||
it == ACCESS_FINE_LOCATION | ||
} | ||
|
||
// Prefer fine location if provided in manifest, otherwise coarse location | ||
return if (declaredPermissions.contains(ACCESS_FINE_LOCATION)) { | ||
ACCESS_FINE_LOCATION | ||
} else if (declaredPermissions.contains(ACCESS_COARSE_LOCATION)) { | ||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.S || | ||
Build.VERSION.SDK_INT == Build.VERSION_CODES.S_V2) { | ||
// Android 12 requires the "fine" permission for location | ||
// access within the WebView. Granting "coarse" location does not | ||
// work. See: https://issues.chromium.org/issues/40205003 | ||
null | ||
} else { | ||
ACCESS_COARSE_LOCATION | ||
} | ||
} else { | ||
null | ||
} | ||
} | ||
|
||
private fun manifestPermissions(): Array<String> { | ||
return try { | ||
val context = session.context | ||
val packageInfo = context.packageManager.getPackageInfo( | ||
context.packageName, | ||
PackageManager.GET_PERMISSIONS | ||
) | ||
|
||
packageInfo.requestedPermissions | ||
} catch (e: PackageManager.NameNotFoundException) { | ||
logError("manifestPermissionsNotAvailable", e) | ||
emptyArray() | ||
} | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
core/src/main/kotlin/dev/hotwire/core/files/util/FileConstants.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
package dev.hotwire.core.files.util | ||
|
||
// Intent activity launcher request codes | ||
const val HOTWIRE_REQUEST_CODE_FILES = 37 | ||
|
||
// Permission activity launcher request codes | ||
const val HOTWIRE_REQUEST_CODE_GEOLOCATION_PERMISSION = 3737 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters