Install
$ agentstack add skill-piyushverma0-android-agent-skills-permissions ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Android Runtime Permissions
Rule 1: Always use Accompanist Permissions in Compose
implementation(libs.accompanist.permissions)
// ✅ Single permission
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CameraScreen() {
val cameraPermission = rememberPermissionState(Manifest.permission.CAMERA)
when {
cameraPermission.status.isGranted -> {
CameraPreview()
}
cameraPermission.status.shouldShowRationale -> {
PermissionRationale(
title = "Camera required",
description = "This feature requires camera access to scan items.",
onRequest = { cameraPermission.launchPermissionRequest() }
)
}
else -> {
// First time or permanently denied
LaunchedEffect(Unit) { cameraPermission.launchPermissionRequest() }
}
}
}
// ✅ Multiple permissions
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun LocationScreen() {
val locationPermissions = rememberMultiplePermissionsState(
listOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
when {
locationPermissions.allPermissionsGranted -> LocationContent()
locationPermissions.shouldShowRationale -> PermissionRationale(
title = "Location required",
description = "We need your location to show nearby items.",
onRequest = { locationPermissions.launchMultiplePermissionRequest() }
)
else -> LaunchedEffect(Unit) { locationPermissions.launchMultiplePermissionRequest() }
}
}
Rule 2: Rationale dialog — always explain before requesting
// ✅ Standard permission rationale composable
@Composable
fun PermissionRationale(
title: String,
description: String,
onRequest: () -> Unit,
onDismiss: () -> Unit = {},
onOpenSettings: (() -> Unit)? = null
) {
AlertDialog(
onDismissRequest = onDismiss,
icon = { Icon(Icons.Default.Info, contentDescription = null) },
title = { Text(title) },
text = { Text(description) },
confirmButton = {
TextButton(onClick = onRequest) { Text("Grant permission") }
},
dismissButton = {
if (onOpenSettings != null) {
TextButton(onClick = onOpenSettings) { Text("Open settings") }
} else {
TextButton(onClick = onDismiss) { Text("Not now") }
}
}
)
}
// ✅ Open app settings when permanently denied
fun Context.openAppSettings() {
startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
})
}
Rule 3: Declare permissions in AndroidManifest
Rule 4: Background location — separate request flow
// ✅ Request foreground location first, then background separately
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun BackgroundLocationScreen() {
val foregroundLocation = rememberMultiplePermissionsState(
listOf(Manifest.permission.ACCESS_FINE_LOCATION)
)
val backgroundLocation = rememberPermissionState(
Manifest.permission.ACCESS_BACKGROUND_LOCATION
)
when {
!foregroundLocation.allPermissionsGranted -> {
// Step 1: request foreground first
RequestForegroundLocation(onRequest = { foregroundLocation.launchMultiplePermissionRequest() })
}
!backgroundLocation.status.isGranted -> {
// Step 2: only after foreground granted
RequestBackgroundLocation(onRequest = { backgroundLocation.launchPermissionRequest() })
}
else -> BackgroundLocationContent()
}
}
Common Mistakes
❌ Requesting permission without rationale — users deny without explanation ❌ Requesting multiple unrelated permissions at once — request only when needed ❌ Not handling permanently denied state — always offer "Open Settings" option ❌ Requesting background location before foreground — Android rejects this ❌ Missing permission in AndroidManifest — request will always be denied ❌ Requesting WRITEEXTERNALSTORAGE on Android 10+ — not needed, use scoped storage
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: piyushverma0
- Source: piyushverma0/android-agent-skills
- License: MIT
- Homepage: https://android-agent-skills.vercel.app
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.