mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-11 00:12:24 +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
|
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.
|
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
|
<activity-alias
|
||||||
android:name=".GearslipUsbAccessory"
|
android:name=".GearslipUsbAccessory"
|
||||||
android:targetActivity=".GearslipActivity"
|
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
|
@Composable
|
||||||
fun PhoneDialerScreen() {
|
fun PhoneDialerScreen() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val hasPermissions = hasCallPermissions(context)
|
var hasPermissions by remember { mutableStateOf(hasCallPermissions(context)) }
|
||||||
var tab by remember { mutableStateOf(TAB_CONTACTS) }
|
var tab by remember { mutableStateOf(TAB_CONTACTS) }
|
||||||
|
|
||||||
Column(Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
Column(Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
@@ -148,7 +148,7 @@ fun PhoneDialerScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!hasPermissions) {
|
if (!hasPermissions) {
|
||||||
MissingPermission(context)
|
MissingPermission(context) { hasPermissions = true }
|
||||||
return@Column
|
return@Column
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,19 +159,23 @@ fun PhoneDialerScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@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)) {
|
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
Text(
|
Text(
|
||||||
"Gearslip needs the Phone and Contacts permissions to dial from here. Grant them " +
|
"Gearslip needs the Phone and Contacts permissions to dial from here. Allow them on " +
|
||||||
"from the app's settings.",
|
"the phone when you're parked.",
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
GsButton(tone = GsTone.Tonal, onClick = {
|
GsButton(tone = GsTone.Tonal, onClick = {
|
||||||
context.startActivity(
|
app.seb3thehacker.gearslip.PermissionActivity.ask(context, CALL_PERMISSIONS)
|
||||||
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", context.packageName, null)),
|
}) { Text("Ask on the phone") }
|
||||||
)
|
|
||||||
}) { Text("Open app settings") }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,12 @@
|
|||||||
<item name="android:windowNoTitle">true</item>
|
<item name="android:windowNoTitle">true</item>
|
||||||
<item name="windowActionBar">false</item>
|
<item name="windowActionBar">false</item>
|
||||||
</style>
|
</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>
|
</resources>
|
||||||
Reference in new issue
Block a user