mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-10 16:02:25 +01:00
phone: ask for call permissions on the phone from the car's Phone screen
This commit is contained in:
1 parent
e2e0d3f8bb
commit
b57bfb5324
4 files changed
+76
-9
No files matched your search
@@ -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.
|
||||
-->
|
||||
<activity
|
||||
android:name=".PermissionActivity"
|
||||
android:exported="false"
|
||||
android:excludeFromRecents="true"
|
||||
android:theme="@style/Theme.Gearslip.Invisible" />
|
||||
|
||||
<activity-alias
|
||||
android:name=".GearslipUsbAccessory"
|
||||
android:targetActivity=".GearslipActivity"
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package app.seb3thehacker.gearslip
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ActivityOptions
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Display
|
||||
|
||||
/**
|
||||
* Asks for runtime permissions on the phone's own screen, for a car screen that can't show
|
||||
* Android's dialog itself. It has no look of its own: the dialog appears, the answer is given,
|
||||
* and it finishes.
|
||||
*/
|
||||
class PermissionActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val wanted = intent.getStringArrayExtra(EXTRA_PERMISSIONS)
|
||||
?.filter { checkSelfPermission(it) != android.content.pm.PackageManager.PERMISSION_GRANTED }
|
||||
.orEmpty()
|
||||
if (wanted.isEmpty() || savedInstanceState != null) {
|
||||
if (wanted.isEmpty()) finish()
|
||||
return
|
||||
}
|
||||
requestPermissions(wanted.toTypedArray(), REQUEST)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, 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<String>) {
|
||||
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}") }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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") }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,4 +9,12 @@
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
</style>
|
||||
|
||||
<!-- For PermissionActivity: only Android's own permission dialog shows, over whatever was there. -->
|
||||
<style name="Theme.Gearslip.Invisible" parent="Theme.Gearslip">
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
Reference in new issue
Block a user