From 666361a1fdb3fc48b110fd10f144e133a91f5163 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Tue, 12 Sep 2023 00:23:27 +0200 Subject: [PATCH] Location: ask for permissions if not granted at time of request --- .../core/src/main/AndroidManifest.xml | 2 +- .../core/src/main/res/values/themes.xml | 11 ++++ .../core/src/main/AndroidManifest.xml | 2 +- .../protocol/msgs/AuthenticatorGetInfo.kt | 2 +- .../gms/fido/core/ui/AuthenticatorActivity.kt | 2 +- .../core/src/main/res/values/styles.xml | 19 ------- .../core/src/main/AndroidManifest.xml | 51 ++++++++++-------- .../location/manager/AskPermissionActivity.kt | 49 +++++++++++++++++ .../location/manager/LastLocationCapsule.kt | 4 ++ .../gms/location/manager/LocationManager.kt | 54 ++++++++++++++++++- 10 files changed, 150 insertions(+), 46 deletions(-) delete mode 100644 play-services-fido/core/src/main/res/values/styles.xml create mode 100644 play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/AskPermissionActivity.kt diff --git a/play-services-auth-api-phone/core/src/main/AndroidManifest.xml b/play-services-auth-api-phone/core/src/main/AndroidManifest.xml index fdf13e4544..21ac4f7dcd 100644 --- a/play-services-auth-api-phone/core/src/main/AndroidManifest.xml +++ b/play-services-auth-api-phone/core/src/main/AndroidManifest.xml @@ -20,7 +20,7 @@ android:name="org.microg.gms.auth.phone.AskPermissionActivity" android:exported="false" android:process=":ui" - android:theme="@style/Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar" /> + android:theme="@style/Theme.Translucent" /> false true + + diff --git a/play-services-fido/core/src/main/AndroidManifest.xml b/play-services-fido/core/src/main/AndroidManifest.xml index 233aaeae2b..484ed5fa8e 100644 --- a/play-services-fido/core/src/main/AndroidManifest.xml +++ b/play-services-fido/core/src/main/AndroidManifest.xml @@ -28,6 +28,6 @@ android:configChanges="orientation|keyboard|keyboardHidden|screenSize" android:exported="false" android:process=":ui" - android:theme="@style/Theme.Fido.Translucent" /> + android:theme="@style/Theme.Translucent" /> diff --git a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorGetInfo.kt b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorGetInfo.kt index 30eb30fb6b..c9d78b4935 100644 --- a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorGetInfo.kt +++ b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/protocol/msgs/AuthenticatorGetInfo.kt @@ -135,7 +135,7 @@ class AuthenticatorGetInfoResponse( uvModality = obj.get(18)?.AsInt32Value(), certifications = obj.get(19)?.entries?.mapNotNull { runCatching { it.key.AsString() to it.value.AsInt32Value() }.getOrNull() }?.toMap(), remainingDiscoverableCredentials = obj.get(20)?.AsInt32Value(), - vendorPrototypeConfigCommands = obj.get(20)?.AsInt32Sequence()?.toList(), + vendorPrototypeConfigCommands = obj.get(21)?.AsInt32Sequence()?.toList(), ) } diff --git a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt index a66aa24daa..fc03b6662e 100644 --- a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt +++ b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt @@ -103,7 +103,7 @@ class AuthenticatorActivity : AppCompatActivity(), TransportHandlerCallback { if (instantTransport != null && instantTransport.transport in INSTANT_SUPPORTED_TRANSPORTS) { window.setBackgroundDrawable(ColorDrawable(0)) window.statusBarColor = Color.TRANSPARENT - setTheme(R.style.Theme_Fido_Translucent) + setTheme(org.microg.gms.base.core.R.style.Theme_Translucent) } } diff --git a/play-services-fido/core/src/main/res/values/styles.xml b/play-services-fido/core/src/main/res/values/styles.xml deleted file mode 100644 index f786056f42..0000000000 --- a/play-services-fido/core/src/main/res/values/styles.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - diff --git a/play-services-location/core/src/main/AndroidManifest.xml b/play-services-location/core/src/main/AndroidManifest.xml index d9687f9692..9b4ac06c89 100644 --- a/play-services-location/core/src/main/AndroidManifest.xml +++ b/play-services-location/core/src/main/AndroidManifest.xml @@ -1,38 +1,47 @@ - - + xmlns:android="http://schemas.android.com/apk/res/android"> - - - - + + + + - - - + + + + + + android:name="org.microg.gms.location.manager.LocationManagerService" + android:exported="true"> - + - + - - + + - + diff --git a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/AskPermissionActivity.kt b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/AskPermissionActivity.kt new file mode 100644 index 0000000000..3214571203 --- /dev/null +++ b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/AskPermissionActivity.kt @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2023 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.location.manager + +import android.content.Intent +import android.os.Bundle +import android.os.Message +import android.os.Messenger +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.os.bundleOf + +const val EXTRA_MESSENGER = "messenger" +const val EXTRA_PERMISSIONS = "permissions" +const val EXTRA_GRANT_RESULTS = "results" + +private const val REQUEST_CODE_PERMISSION = 120 + +class AskPermissionActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val permissions = intent?.getStringArrayExtra(EXTRA_PERMISSIONS) ?: emptyArray() + ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_PERMISSION) + } + + private fun sendReply(code: Int = RESULT_OK, extras: Bundle = Bundle.EMPTY) { + intent?.getParcelableExtra(EXTRA_MESSENGER)?.let { + runCatching { + it.send(Message.obtain().apply { + what = code + data = extras + }) + } + } + setResult(code, Intent().apply { putExtras(extras) }) + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + if (requestCode == REQUEST_CODE_PERMISSION) { + sendReply(extras = bundleOf(EXTRA_GRANT_RESULTS to grantResults)) + finish() + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + } + } +} \ No newline at end of file diff --git a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LastLocationCapsule.kt b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LastLocationCapsule.kt index 642c3d8783..0df8f843c2 100644 --- a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LastLocationCapsule.kt +++ b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LastLocationCapsule.kt @@ -111,6 +111,10 @@ class LastLocationCapsule(private val context: Context) { Log.w(TAG, e) // Ignore } + fetchFromSystem() + } + + fun fetchFromSystem() { val locationManager = context.getSystemService() ?: return try { locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)?.let { updateCoarseLocation(it) } diff --git a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt index a652e861d8..eec89ed677 100644 --- a/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt +++ b/play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationManager.kt @@ -6,6 +6,7 @@ package org.microg.gms.location.manager import android.Manifest +import android.app.Activity import android.app.PendingIntent import android.app.PendingIntent.FLAG_MUTABLE import android.app.PendingIntent.FLAG_UPDATE_CURRENT @@ -13,10 +14,10 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.location.Location -import android.location.LocationManager +import android.os.* import android.os.Build.VERSION.SDK_INT -import android.os.IBinder import android.util.Log +import androidx.core.content.ContextCompat import androidx.core.content.getSystemService import androidx.core.location.LocationListenerCompat import androidx.core.location.LocationManagerCompat @@ -29,6 +30,10 @@ import com.google.android.gms.location.Granularity.GRANULARITY_COARSE import com.google.android.gms.location.Granularity.GRANULARITY_FINE import com.google.android.gms.location.Priority.PRIORITY_HIGH_ACCURACY import com.google.android.gms.location.internal.ClientIdentity +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.microg.gms.location.* import org.microg.gms.utils.IntentCacheManager import java.io.PrintWriter @@ -45,6 +50,8 @@ class LocationManager(private val context: Context, private val lifecycle: Lifec private val gpsLocationListener by lazy { LocationListenerCompat { updateGpsLocation(it) } } private val networkLocationListener by lazy { LocationListenerCompat { updateNetworkLocation(it) } } private var boundToSystemNetworkLocation: Boolean = false + private val activePermissionRequestLock = Mutex() + private var activePermissionRequest: Deferred? = null val deviceOrientationManager = DeviceOrientationManager(context, lifecycle) @@ -72,6 +79,7 @@ class LocationManager(private val context: Context, private val lifecycle: Lifec // No last location available at requested granularity due to lack of permission null } else { + ensurePermissions() val preLocation = lastLocationCapsule.getLocation(effectiveGranularity, request.maxUpdateAgeMillis) val processedLocation = postProcessor.process(preLocation, effectiveGranularity, clientIdentity.isGoogle(context)) if (!context.noteAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) { @@ -103,6 +111,7 @@ class LocationManager(private val context: Context, private val lifecycle: Lifec suspend fun addBinderRequest(clientIdentity: ClientIdentity, binder: IBinder, callback: ILocationCallback, request: LocationRequest) { request.verify(context, clientIdentity) + ensurePermissions() requestManager.add(binder, clientIdentity, callback, request, lastLocationCapsule) } @@ -123,6 +132,7 @@ class LocationManager(private val context: Context, private val lifecycle: Lifec suspend fun addIntentRequest(clientIdentity: ClientIdentity, pendingIntent: PendingIntent, request: LocationRequest) { request.verify(context, clientIdentity) + ensurePermissions() requestManager.add(pendingIntent, clientIdentity, request, lastLocationCapsule) } @@ -243,6 +253,46 @@ class LocationManager(private val context: Context, private val lifecycle: Lifec lastLocationCapsule.getLocation(GRANULARITY_FINE, Long.MAX_VALUE)?.let { deviceOrientationManager.onLocationChanged(it) } } + private suspend fun ensurePermissions(): Boolean { + if (SDK_INT < 23) + return true + + val permissions = mutableListOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION) + if (SDK_INT >= 29) permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION) + + if (permissions.all { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED }) + return true + + val (completable, deferred) = activePermissionRequestLock.withLock { + if (activePermissionRequest == null) { + val completable = CompletableDeferred() + activePermissionRequest = completable + completable to activePermissionRequest!! + } else { + null to activePermissionRequest!! + } + } + if (completable != null) { + val intent = Intent(context, AskPermissionActivity::class.java) + intent.putExtra(EXTRA_MESSENGER, Messenger(object : Handler(Looper.getMainLooper()) { + override fun handleMessage(msg: Message) { + if (msg.what == Activity.RESULT_OK) { + lastLocationCapsule.fetchFromSystem() + onRequestManagerUpdated() + val grantResults = msg.data?.getIntArray(EXTRA_GRANT_RESULTS) ?: IntArray(0) + completable.complete(grantResults.size == permissions.size && grantResults.all { it == PackageManager.PERMISSION_GRANTED }) + } else { + completable.complete(false) + } + } + })) + intent.putExtra(EXTRA_PERMISSIONS, permissions.toTypedArray()) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } + return deferred.await() + } + fun dump(writer: PrintWriter) { writer.println("Location availability: ${lastLocationCapsule.locationAvailability}") writer.println("Last coarse location: ${postProcessor.process(lastLocationCapsule.getLocation(GRANULARITY_COARSE, Long.MAX_VALUE), GRANULARITY_COARSE, true)}")