diff --git a/gearslip/src/main/AndroidManifest.xml b/gearslip/src/main/AndroidManifest.xml index c683230..b54c265 100644 --- a/gearslip/src/main/AndroidManifest.xml +++ b/gearslip/src/main/AndroidManifest.xml @@ -162,6 +162,12 @@ activity so Settings can switch off just this (AppSettings.setGearslipEnabled) and leave the head unit to Android Auto, without disabling the screen the switch is on. --> + + , grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + GearslipLog.i("permissions: ${permissions.zip(grantResults.toList()).joinToString { (p, r) -> "${p.substringAfterLast('.')}=${r == 0}" }}") + finish() + } + + companion object { + private const val EXTRA_PERMISSIONS = "permissions" + private const val REQUEST = 1 + + /** Shows the permission dialog on the phone, whichever screen [context] belongs to. */ + fun ask(context: Context, permissions: Array) { + val intent = Intent(context, PermissionActivity::class.java) + .putExtra(EXTRA_PERMISSIONS, permissions) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + val options = ActivityOptions.makeBasic().setLaunchDisplayId(Display.DEFAULT_DISPLAY) + runCatching { context.startActivity(intent, options.toBundle()) } + .onFailure { GearslipLog.w("permissions: could not ask on the phone: ${it.message}") } + } + } +} diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/PhoneDialerScreen.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/PhoneDialerScreen.kt index ad215fe..e691c23 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/PhoneDialerScreen.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/PhoneDialerScreen.kt @@ -133,7 +133,7 @@ private const val TAB_KEYPAD = 1 @Composable fun PhoneDialerScreen() { val context = LocalContext.current - val hasPermissions = hasCallPermissions(context) + var hasPermissions by remember { mutableStateOf(hasCallPermissions(context)) } var tab by remember { mutableStateOf(TAB_CONTACTS) } Column(Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { @@ -148,7 +148,7 @@ fun PhoneDialerScreen() { } if (!hasPermissions) { - MissingPermission(context) + MissingPermission(context) { hasPermissions = true } return@Column } @@ -159,19 +159,23 @@ fun PhoneDialerScreen() { } @Composable -private fun MissingPermission(context: Context) { +private fun MissingPermission(context: Context, onGranted: () -> Unit) { + // Android's dialog can't show on the car screen, so it opens on the phone; checking again + // every second picks the answer up without the driver having to come back in. + androidx.compose.runtime.LaunchedEffect(Unit) { + while (!hasCallPermissions(context)) kotlinx.coroutines.delay(1_000) + onGranted() + } Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { Text( - "Gearslip needs the Phone and Contacts permissions to dial from here. Grant them " + - "from the app's settings.", + "Gearslip needs the Phone and Contacts permissions to dial from here. Allow them on " + + "the phone when you're parked.", style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant, ) GsButton(tone = GsTone.Tonal, onClick = { - context.startActivity( - Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", context.packageName, null)), - ) - }) { Text("Open app settings") } + app.seb3thehacker.gearslip.PermissionActivity.ask(context, CALL_PERMISSIONS) + }) { Text("Ask on the phone") } } } diff --git a/gearslip/src/main/res/values/themes.xml b/gearslip/src/main/res/values/themes.xml index fa51d18..5a71aa0 100644 --- a/gearslip/src/main/res/values/themes.xml +++ b/gearslip/src/main/res/values/themes.xml @@ -9,4 +9,12 @@ true false + + +