Implementation
const mediumRiskPermissions = [
PermissionInfo(
permission: 'android.permission.ACCESS_FINE_LOCATION',
risk: PermissionRisk.medium,
category: 'Location',
reason: 'Accesses the user\'s precise location.',
recommendation:
'Use ACCESS_COARSE_LOCATION if precise location is not required for the core feature.',
),
PermissionInfo(
permission: 'android.permission.ACCESS_COARSE_LOCATION',
risk: PermissionRisk.medium,
category: 'Location',
reason: 'Accesses the user\'s approximate location.',
recommendation:
'Request location only when necessary and provide clear in-app justification.',
),
PermissionInfo(
permission: 'android.permission.READ_MEDIA_IMAGES',
risk: PermissionRisk.medium,
category: 'Media',
reason: 'Accesses all photos on the device.',
recommendation:
'Use the Android Photo Picker instead — it requires no permission and is privacy-preserving. '
'Declaration required if this permission is kept.',
),
PermissionInfo(
permission: 'android.permission.READ_MEDIA_VIDEO',
risk: PermissionRisk.medium,
category: 'Media',
reason: 'Accesses all videos on the device.',
recommendation:
'Use the Android Photo Picker instead. Declaration required if this permission is kept.',
),
PermissionInfo(
permission: 'android.permission.READ_MEDIA_AUDIO',
risk: PermissionRisk.medium,
category: 'Media',
reason: 'Accesses all audio files on the device.',
recommendation: 'Scope to app-specific media directories where possible.',
),
PermissionInfo(
permission: 'android.permission.READ_CONTACTS',
risk: PermissionRisk.medium,
category: 'Contacts',
reason: 'Reads the user\'s full contact list.',
recommendation:
'Use the Android Contact Picker for single-contact selection instead of broad access. '
'Broad access will require justification under Google\'s new Contacts Permissions policy (effective Oct 28, 2026).',
),
PermissionInfo(
permission: 'android.permission.WRITE_CONTACTS',
risk: PermissionRisk.medium,
category: 'Contacts',
reason: 'Modifies the user\'s contact list.',
recommendation:
'Only request if the app explicitly creates/edits contacts as a core feature.',
),
PermissionInfo(
permission: 'android.permission.CAMERA',
risk: PermissionRisk.medium,
category: 'Camera',
reason: 'Accesses the device camera.',
recommendation:
'Request at time of use (runtime permission) with a clear in-context explanation.',
),
PermissionInfo(
permission: 'android.permission.RECORD_AUDIO',
risk: PermissionRisk.medium,
category: 'Microphone',
reason: 'Accesses the device microphone.',
recommendation:
'Request only when the recording feature is actively used; stop capture immediately after use.',
),
PermissionInfo(
permission: 'android.permission.READ_PHONE_STATE',
risk: PermissionRisk.medium,
category: 'Telephony',
reason:
'Reads device identifiers and phone state (IMEI, call state, etc.).',
recommendation:
'Use Firebase Instance ID / Advertising ID / SDK-generated UUIDs instead of device identifiers where possible.',
),
PermissionInfo(
permission: 'android.permission.READ_PHONE_NUMBERS',
risk: PermissionRisk.medium,
category: 'Telephony',
reason: 'Reads the device\'s phone number(s).',
recommendation:
'Use SMS Retriever / phone number hint APIs for verification flows instead.',
),
PermissionInfo(
permission: 'android.permission.USE_EXACT_ALARM',
risk: PermissionRisk.medium,
category: 'Alarms',
reason:
'Schedules precisely-timed alarms; auto-granted only for alarm/calendar apps.',
recommendation:
'Use SCHEDULE_EXACT_ALARM (user-granted) instead unless the app\'s core function is an alarm, timer, or calendar with event notifications.',
),
PermissionInfo(
permission: 'android.permission.USE_FULL_SCREEN_INTENT',
risk: PermissionRisk.medium,
category: 'Notifications',
reason:
'Shows a full-screen notification, interrupting whatever the user is doing.',
recommendation:
'Auto-granted only for alarm apps or calling apps on Android 14+. Otherwise, request explicit user consent.',
),
PermissionInfo(
permission: 'android.permission.READ_EXTERNAL_STORAGE',
risk: PermissionRisk.medium,
category: 'Storage',
reason: 'Reads files from shared/external storage.',
recommendation:
'On Android 13+, prefer scoped media permissions (READ_MEDIA_IMAGES/VIDEO/AUDIO) or the Storage Access Framework.',
),
PermissionInfo(
permission: 'android.permission.WRITE_EXTERNAL_STORAGE',
risk: PermissionRisk.medium,
category: 'Storage',
reason: 'Writes files to shared/external storage.',
recommendation:
'Use app-specific storage or the MediaStore API instead; largely unnecessary on Android 10+ (scoped storage).',
),
PermissionInfo(
permission: 'android.permission.ACTIVITY_RECOGNITION',
risk: PermissionRisk.medium,
category: 'Sensors',
reason:
'Detects the user\'s physical activity (walking, running, driving, etc.).',
recommendation:
'Request only if activity-based features are core to the app (e.g., fitness tracking).',
),
PermissionInfo(
permission: 'android.permission.BLUETOOTH_CONNECT',
risk: PermissionRisk.medium,
category: 'Bluetooth',
reason: 'Connects to already-paired Bluetooth devices.',
recommendation:
'Request only when a Bluetooth-dependent feature is actively used.',
),
PermissionInfo(
permission: 'android.permission.BLUETOOTH_SCAN',
risk: PermissionRisk.medium,
category: 'Bluetooth',
reason:
'Scans for nearby Bluetooth devices (can be used to infer location).',
recommendation:
'Add android:usesPermissionFlags="neverForLocation" if location derivation is not needed, to avoid also requiring location permissions.',
),
PermissionInfo(
permission: 'android.permission.NEARBY_WIFI_DEVICES',
risk: PermissionRisk.medium,
category: 'WiFi',
reason: 'Discovers and connects to nearby WiFi devices.',
recommendation:
'Request only when a WiFi-based discovery/connection feature is active.',
),
];