From bfa686e5cb653f8b4dec1e689c0d3f171b2f681f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 1 Jan 2026 09:46:10 +0000
Subject: [PATCH 1/5] Initial plan
From 06595eabed2657d2b608ef1e609388d3a4258d85 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 1 Jan 2026 09:50:21 +0000
Subject: [PATCH 2/5] Declare comprehensive permissions
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
---
android/app/src/main/AndroidManifest.xml | 80 ++++++++++++++++-
app.config.js | 106 ++++++++++++++++++++++-
2 files changed, 183 insertions(+), 3 deletions(-)
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 5d65bc1..664e1a7 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,15 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
@@ -42,4 +118,4 @@
-
\ No newline at end of file
+
diff --git a/app.config.js b/app.config.js
index d9f67bd..e40bb71 100644
--- a/app.config.js
+++ b/app.config.js
@@ -80,6 +80,22 @@ module.exports = {
// Provide your Google Maps API key
googleMapsApiKey: 'YOUR_IOS_GOOGLE_MAPS_API_KEY',
},
+ infoPlist: {
+ NSCameraUsageDescription: 'Allow CodeBuilder Admin to access the camera for capturing photos and video.',
+ NSMicrophoneUsageDescription: 'Allow CodeBuilder Admin to access the microphone for calls, audio, and video capture.',
+ NSPhotoLibraryUsageDescription: 'Allow CodeBuilder Admin to access your photo library to select media.',
+ NSPhotoLibraryAddUsageDescription: 'Allow CodeBuilder Admin to save photos or videos to your library.',
+ NSLocationWhenInUseUsageDescription: 'Allow CodeBuilder Admin to access your location while using the app.',
+ NSLocationAlwaysAndWhenInUseUsageDescription: 'Allow CodeBuilder Admin to access your location even when the app is not active.',
+ NSCalendarsUsageDescription: 'Allow CodeBuilder Admin to access your calendars.',
+ NSContactsUsageDescription: 'Allow CodeBuilder Admin to access your contacts.',
+ NSBluetoothAlwaysUsageDescription: 'Allow CodeBuilder Admin to use Bluetooth for nearby devices.',
+ NSBluetoothPeripheralUsageDescription: 'Allow CodeBuilder Admin to use Bluetooth peripherals.',
+ NSMotionUsageDescription: 'Allow CodeBuilder Admin to access motion data.',
+ NSSpeechRecognitionUsageDescription: 'Allow CodeBuilder Admin to transcribe speech.',
+ NSFaceIDUsageDescription: 'Allow CodeBuilder Admin to use Face ID for authentication.',
+ NSUserTrackingUsageDescription: 'Allow CodeBuilder Admin to track activity for personalized experiences.',
+ },
},
android: {
versionCode: versionData.androidVersionCode, // Using Android versionCode from version.json
@@ -88,7 +104,95 @@ module.exports = {
backgroundColor: '#ffffff',
},
package: 'com.digitalnomad91.codebuilderadmin',
- permissions: ['NOTIFICATIONS', 'POST_NOTIFICATIONS', 'READ_PHONE_STATE'],
+ permissions: [
+ 'ACCEPT_HANDOVER',
+ 'ACCESS_BACKGROUND_LOCATION',
+ 'ACCESS_COARSE_LOCATION',
+ 'ACCESS_FINE_LOCATION',
+ 'ACCESS_MEDIA_LOCATION',
+ 'ACCESS_NETWORK_STATE',
+ 'ACCESS_NOTIFICATION_POLICY',
+ 'ACCESS_WIFI_STATE',
+ 'ACTIVITY_RECOGNITION',
+ 'ADD_VOICEMAIL',
+ 'ANSWER_PHONE_CALLS',
+ 'AUTHENTICATE_ACCOUNTS',
+ 'BLUETOOTH',
+ 'BLUETOOTH_ADMIN',
+ 'BLUETOOTH_ADVERTISE',
+ 'BLUETOOTH_CONNECT',
+ 'BLUETOOTH_SCAN',
+ 'BODY_SENSORS',
+ 'BODY_SENSORS_BACKGROUND',
+ 'CALL_PHONE',
+ 'CAMERA',
+ 'CHANGE_NETWORK_STATE',
+ 'CHANGE_WIFI_MULTICAST_STATE',
+ 'CHANGE_WIFI_STATE',
+ 'FOREGROUND_SERVICE',
+ 'FOREGROUND_SERVICE_CAMERA',
+ 'FOREGROUND_SERVICE_CONNECTED_DEVICE',
+ 'FOREGROUND_SERVICE_DATA_SYNC',
+ 'FOREGROUND_SERVICE_HEALTH',
+ 'FOREGROUND_SERVICE_LOCATION',
+ 'FOREGROUND_SERVICE_MEDIA_PLAYBACK',
+ 'FOREGROUND_SERVICE_MICROPHONE',
+ 'FOREGROUND_SERVICE_PHONE_CALL',
+ 'FOREGROUND_SERVICE_REMOTE_MESSAGING',
+ 'GET_ACCOUNTS',
+ 'INTERNET',
+ 'KILL_BACKGROUND_PROCESSES',
+ 'MANAGE_EXTERNAL_STORAGE',
+ 'MODIFY_AUDIO_SETTINGS',
+ 'NEARBY_WIFI_DEVICES',
+ 'NFC',
+ 'NFC_TRANSACTION_EVENT',
+ 'NOTIFICATIONS',
+ 'PACKAGE_USAGE_STATS',
+ 'POST_NOTIFICATIONS',
+ 'PROCESS_OUTGOING_CALLS',
+ 'QUERY_ALL_PACKAGES',
+ 'READ_CALENDAR',
+ 'WRITE_CALENDAR',
+ 'READ_CALL_LOG',
+ 'WRITE_CALL_LOG',
+ 'READ_CONTACTS',
+ 'WRITE_CONTACTS',
+ 'READ_EXTERNAL_STORAGE',
+ 'WRITE_EXTERNAL_STORAGE',
+ 'READ_MEDIA_AUDIO',
+ 'READ_MEDIA_IMAGES',
+ 'READ_MEDIA_VIDEO',
+ 'READ_MEDIA_VISUAL_USER_SELECTED',
+ 'READ_PHONE_NUMBERS',
+ 'READ_PHONE_STATE',
+ 'READ_PRECISE_PHONE_STATE',
+ 'READ_PROFILE',
+ 'READ_SMS',
+ 'RECEIVE_BOOT_COMPLETED',
+ 'RECEIVE_MMS',
+ 'RECEIVE_SMS',
+ 'RECEIVE_WAP_PUSH',
+ 'RECORD_AUDIO',
+ 'REORDER_TASKS',
+ 'REQUEST_IGNORE_BATTERY_OPTIMIZATIONS',
+ 'REQUEST_INSTALL_PACKAGES',
+ 'SCHEDULE_EXACT_ALARM',
+ 'SEND_SMS',
+ 'SET_WALLPAPER',
+ 'SET_WALLPAPER_HINTS',
+ 'SYSTEM_ALERT_WINDOW',
+ 'USE_BIOMETRIC',
+ 'USE_CREDENTIALS',
+ 'USE_FULL_SCREEN_INTENT',
+ 'USE_FINGERPRINT',
+ 'USE_SIP',
+ 'VIBRATE',
+ 'WAKE_LOCK',
+ 'WRITE_SYNC_SETTINGS',
+ 'READ_SYNC_SETTINGS',
+ 'READ_SYNC_STATS',
+ ],
googleServicesFile: './google-services.json',
useNextNotificationsApi: true,
notification: {
From 6f4302d1ea8bceca42f75189faa4baa7520cb048 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 1 Jan 2026 10:12:45 +0000
Subject: [PATCH 3/5] Add permissions demos and merge main
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
---
app.config.js | 466 ++++++++++++++----
app/(tabs)/_layout.tsx | 7 +
app/(tabs)/permissions/camera-mic.tsx | 18 +
app/(tabs)/permissions/connectivity.tsx | 18 +
app/(tabs)/permissions/index.tsx | 60 +++
app/(tabs)/permissions/location.tsx | 18 +
app/(tabs)/permissions/media-storage.tsx | 18 +
app/(tabs)/permissions/notifications.tsx | 18 +
app/(tabs)/permissions/storage.tsx | 18 +
app/(tabs)/permissions/telephony-sms.tsx | 18 +
assets/permissions-hub.png | Bin 0 -> 25807 bytes
.../BluetoothNearbyPermissionDemo.tsx | 55 +++
.../CameraMicrophonePermissionDemo.tsx | 46 ++
.../permissions/LocationPermissionDemo.tsx | 63 +++
.../MediaLibraryPermissionDemo.tsx | 47 ++
.../NotificationsPermissionDemo.tsx | 52 ++
.../permissions/StoragePermissionDemo.tsx | 56 +++
.../TelephonySmsPermissionDemo.tsx | 57 +++
version.json | 6 +-
19 files changed, 953 insertions(+), 88 deletions(-)
create mode 100644 app/(tabs)/permissions/camera-mic.tsx
create mode 100644 app/(tabs)/permissions/connectivity.tsx
create mode 100644 app/(tabs)/permissions/index.tsx
create mode 100644 app/(tabs)/permissions/location.tsx
create mode 100644 app/(tabs)/permissions/media-storage.tsx
create mode 100644 app/(tabs)/permissions/notifications.tsx
create mode 100644 app/(tabs)/permissions/storage.tsx
create mode 100644 app/(tabs)/permissions/telephony-sms.tsx
create mode 100644 assets/permissions-hub.png
create mode 100644 components/permissions/BluetoothNearbyPermissionDemo.tsx
create mode 100644 components/permissions/CameraMicrophonePermissionDemo.tsx
create mode 100644 components/permissions/LocationPermissionDemo.tsx
create mode 100644 components/permissions/MediaLibraryPermissionDemo.tsx
create mode 100644 components/permissions/NotificationsPermissionDemo.tsx
create mode 100644 components/permissions/StoragePermissionDemo.tsx
create mode 100644 components/permissions/TelephonySmsPermissionDemo.tsx
diff --git a/app.config.js b/app.config.js
index e40bb71..8c92868 100644
--- a/app.config.js
+++ b/app.config.js
@@ -105,93 +105,389 @@ module.exports = {
},
package: 'com.digitalnomad91.codebuilderadmin',
permissions: [
- 'ACCEPT_HANDOVER',
- 'ACCESS_BACKGROUND_LOCATION',
- 'ACCESS_COARSE_LOCATION',
- 'ACCESS_FINE_LOCATION',
- 'ACCESS_MEDIA_LOCATION',
- 'ACCESS_NETWORK_STATE',
- 'ACCESS_NOTIFICATION_POLICY',
- 'ACCESS_WIFI_STATE',
- 'ACTIVITY_RECOGNITION',
- 'ADD_VOICEMAIL',
- 'ANSWER_PHONE_CALLS',
- 'AUTHENTICATE_ACCOUNTS',
- 'BLUETOOTH',
- 'BLUETOOTH_ADMIN',
- 'BLUETOOTH_ADVERTISE',
- 'BLUETOOTH_CONNECT',
- 'BLUETOOTH_SCAN',
- 'BODY_SENSORS',
- 'BODY_SENSORS_BACKGROUND',
- 'CALL_PHONE',
- 'CAMERA',
- 'CHANGE_NETWORK_STATE',
- 'CHANGE_WIFI_MULTICAST_STATE',
- 'CHANGE_WIFI_STATE',
- 'FOREGROUND_SERVICE',
- 'FOREGROUND_SERVICE_CAMERA',
- 'FOREGROUND_SERVICE_CONNECTED_DEVICE',
- 'FOREGROUND_SERVICE_DATA_SYNC',
- 'FOREGROUND_SERVICE_HEALTH',
- 'FOREGROUND_SERVICE_LOCATION',
- 'FOREGROUND_SERVICE_MEDIA_PLAYBACK',
- 'FOREGROUND_SERVICE_MICROPHONE',
- 'FOREGROUND_SERVICE_PHONE_CALL',
- 'FOREGROUND_SERVICE_REMOTE_MESSAGING',
- 'GET_ACCOUNTS',
- 'INTERNET',
- 'KILL_BACKGROUND_PROCESSES',
- 'MANAGE_EXTERNAL_STORAGE',
- 'MODIFY_AUDIO_SETTINGS',
- 'NEARBY_WIFI_DEVICES',
- 'NFC',
- 'NFC_TRANSACTION_EVENT',
'NOTIFICATIONS',
- 'PACKAGE_USAGE_STATS',
'POST_NOTIFICATIONS',
- 'PROCESS_OUTGOING_CALLS',
- 'QUERY_ALL_PACKAGES',
- 'READ_CALENDAR',
- 'WRITE_CALENDAR',
- 'READ_CALL_LOG',
- 'WRITE_CALL_LOG',
- 'READ_CONTACTS',
- 'WRITE_CONTACTS',
- 'READ_EXTERNAL_STORAGE',
- 'WRITE_EXTERNAL_STORAGE',
- 'READ_MEDIA_AUDIO',
- 'READ_MEDIA_IMAGES',
- 'READ_MEDIA_VIDEO',
- 'READ_MEDIA_VISUAL_USER_SELECTED',
- 'READ_PHONE_NUMBERS',
- 'READ_PHONE_STATE',
- 'READ_PRECISE_PHONE_STATE',
- 'READ_PROFILE',
- 'READ_SMS',
- 'RECEIVE_BOOT_COMPLETED',
- 'RECEIVE_MMS',
- 'RECEIVE_SMS',
- 'RECEIVE_WAP_PUSH',
- 'RECORD_AUDIO',
- 'REORDER_TASKS',
- 'REQUEST_IGNORE_BATTERY_OPTIMIZATIONS',
- 'REQUEST_INSTALL_PACKAGES',
- 'SCHEDULE_EXACT_ALARM',
- 'SEND_SMS',
- 'SET_WALLPAPER',
- 'SET_WALLPAPER_HINTS',
- 'SYSTEM_ALERT_WINDOW',
- 'USE_BIOMETRIC',
- 'USE_CREDENTIALS',
- 'USE_FULL_SCREEN_INTENT',
- 'USE_FINGERPRINT',
- 'USE_SIP',
- 'VIBRATE',
- 'WAKE_LOCK',
- 'WRITE_SYNC_SETTINGS',
- 'READ_SYNC_SETTINGS',
- 'READ_SYNC_STATS',
+ 'android.permission.READ_PHONE_STATE',
+ 'android.permission.ACCESS_ALL_DOWNLOADS',
+ 'android.permission.ACCESS_BLUETOOTH_SHARE',
+ 'android.permission.ACCESS_CACHE_FILESYSTEM',
+ 'android.permission.ACCESS_CHECKIN_PROPERTIES',
+ 'android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY',
+ 'android.permission.ACCESS_DOWNLOAD_MANAGER',
+ 'android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED',
+ 'android.permission.ACCESS_DRM_CERTIFICATES',
+ 'android.permission.ACCESS_EPHEMERAL_APPS',
+ 'android.permission.ACCESS_FM_RADIO',
+ 'android.permission.ACCESS_INPUT_FLINGER',
+ 'android.permission.ACCESS_KEYGUARD_SECURE_STORAGE',
+ 'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS',
+ 'android.permission.ACCESS_MOCK_LOCATION',
+ 'android.permission.ACCESS_MTP',
+ 'android.permission.ACCESS_NETWORK_CONDITIONS',
+ 'android.permission.ACCESS_NETWORK_STATE',
+ 'android.permission.ACCESS_NOTIFICATIONS',
+ 'android.permission.ACCESS_NOTIFICATION_POLICY',
+ 'android.permission.ACCESS_PDB_STATE',
+ 'android.permission.ACCESS_SURFACE_FLINGER',
+ 'android.permission.ACCESS_VOICE_INTERACTION_SERVICE',
+ 'android.permission.ACCESS_VR_MANAGER',
+ 'android.permission.ACCESS_WIFI_STATE',
+ 'android.permission.ACCESS_WIMAX_STATE',
+ 'android.permission.ACCESS_BACKGROUND_LOCATION',
+ 'android.permission.ACCESS_COARSE_LOCATION',
+ 'android.permission.ACCESS_FINE_LOCATION',
+ 'android.permission.ACCESS_MEDIA_LOCATION',
+ 'android.permission.ACCEPT_HANDOVER',
+ 'android.permission.ACCOUNT_MANAGER',
+ 'android.permission.ACTIVITY_RECOGNITION',
+ 'android.permission.ADD_VOICEMAIL',
+ 'android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK',
+ 'android.permission.ANSWER_PHONE_CALLS',
+ 'android.permission.ASEC_ACCESS',
+ 'android.permission.ASEC_CREATE',
+ 'android.permission.ASEC_DESTROY',
+ 'android.permission.ASEC_MOUNT_UNMOUNT',
+ 'android.permission.ASEC_RENAME',
+ 'android.permission.AUTHENTICATE_ACCOUNTS',
+ 'android.permission.BACKUP',
+ 'android.permission.BATTERY_STATS',
+ 'android.permission.BIND_ACCESSIBILITY_SERVICE',
+ 'android.permission.BIND_APPWIDGET',
+ 'android.permission.BIND_CARRIER_MESSAGING_SERVICE',
+ 'android.permission.BIND_CARRIER_SERVICES',
+ 'android.permission.BIND_CHOOSER_TARGET_SERVICE',
+ 'android.permission.BIND_CONDITION_PROVIDER_SERVICE',
+ 'android.permission.BIND_CONNECTION_SERVICE',
+ 'android.permission.BIND_DEVICE_ADMIN',
+ 'android.permission.BIND_DIRECTORY_SEARCH',
+ 'android.permission.BIND_DREAM_SERVICE',
+ 'android.permission.BIND_INCALL_SERVICE',
+ 'android.permission.BIND_INPUT_METHOD',
+ 'android.permission.BIND_INTENT_FILTER_VERIFIER',
+ 'android.permission.BIND_JOB_SERVICE',
+ 'android.permission.BIND_KEYGUARD_APPWIDGET',
+ 'android.permission.BIND_MIDI_DEVICE_SERVICE',
+ 'android.permission.BIND_NFC_SERVICE',
+ 'android.permission.BIND_NOTIFICATION_LISTENER_SERVICE',
+ 'android.permission.BIND_NOTIFICATION_RANKER_SERVICE',
+ 'android.permission.BIND_PACKAGE_VERIFIER',
+ 'android.permission.BIND_PRINT_RECOMMENDATION_SERVICE',
+ 'android.permission.BIND_PRINT_SERVICE',
+ 'android.permission.BIND_PRINT_SPOOLER_SERVICE',
+ 'android.permission.BIND_QUICK_SETTINGS_TILE',
+ 'android.permission.BIND_REMOTEVIEWS',
+ 'android.permission.BIND_REMOTE_DISPLAY',
+ 'android.permission.BIND_ROUTE_PROVIDER',
+ 'android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE',
+ 'android.permission.BIND_SCREENING_SERVICE',
+ 'android.permission.BIND_TELECOM_CONNECTION_SERVICE',
+ 'android.permission.BIND_TEXT_SERVICE',
+ 'android.permission.BIND_TRUST_AGENT',
+ 'android.permission.BIND_TV_INPUT',
+ 'android.permission.BIND_TV_REMOTE_SERVICE',
+ 'android.permission.BIND_VOICE_INTERACTION',
+ 'android.permission.BIND_VPN_SERVICE',
+ 'android.permission.BIND_VR_LISTENER_SERVICE',
+ 'android.permission.BIND_WALLPAPER',
+ 'android.permission.BLUETOOTH',
+ 'android.permission.BLUETOOTH_ADMIN',
+ 'android.permission.BLUETOOTH_ADVERTISE',
+ 'android.permission.BLUETOOTH_CONNECT',
+ 'android.permission.BLUETOOTH_MAP',
+ 'android.permission.BLUETOOTH_PRIVILEGED',
+ 'android.permission.BLUETOOTH_SCAN',
+ 'android.permission.BLUETOOTH_STACK',
+ 'android.permission.BODY_SENSORS',
+ 'android.permission.BODY_SENSORS_BACKGROUND',
+ 'android.permission.BRICK',
+ 'android.permission.BROADCAST_CALLLOG_INFO',
+ 'android.permission.BROADCAST_NETWORK_PRIVILEGED',
+ 'android.permission.BROADCAST_PACKAGE_REMOVED',
+ 'android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION',
+ 'android.permission.BROADCAST_SMS',
+ 'android.permission.BROADCAST_STICKY',
+ 'android.permission.BROADCAST_WAP_PUSH',
+ 'android.permission.CACHE_CONTENT',
+ 'android.permission.CALL_PHONE',
+ 'android.permission.CALL_PRIVILEGED',
+ 'android.permission.CAMERA',
+ 'android.permission.CAMERA_DISABLE_TRANSMIT_LED',
+ 'android.permission.CAMERA_SEND_SYSTEM_EVENTS',
+ 'android.permission.CAPTURE_AUDIO_HOTWORD',
+ 'android.permission.CAPTURE_AUDIO_OUTPUT',
+ 'android.permission.CAPTURE_SECURE_VIDEO_OUTPUT',
+ 'android.permission.CAPTURE_TV_INPUT',
+ 'android.permission.CAPTURE_VIDEO_OUTPUT',
+ 'android.permission.CARRIER_FILTER_SMS',
+ 'android.permission.CHANGE_APP_IDLE_STATE',
+ 'android.permission.CHANGE_BACKGROUND_DATA_SETTING',
+ 'android.permission.CHANGE_COMPONENT_ENABLED_STATE',
+ 'android.permission.CHANGE_CONFIGURATION',
+ 'android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST',
+ 'android.permission.CHANGE_NETWORK_STATE',
+ 'android.permission.CHANGE_WIFI_MULTICAST_STATE',
+ 'android.permission.CHANGE_WIFI_STATE',
+ 'android.permission.CHANGE_WIMAX_STATE',
+ 'android.permission.CLEAR_APP_CACHE',
+ 'android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS',
+ 'android.permission.CLEAR_APP_USER_DATA',
+ 'android.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM',
+ 'android.permission.CONFIGURE_WIFI_DISPLAY',
+ 'android.permission.CONFIRM_FULL_BACKUP',
+ 'android.permission.CONNECTIVITY_INTERNAL',
+ 'android.permission.CONTROL_INCALL_EXPERIENCE',
+ 'android.permission.CONTROL_KEYGUARD',
+ 'android.permission.CONTROL_LOCATION_UPDATES',
+ 'android.permission.CONTROL_VPN',
+ 'android.permission.CONTROL_WIFI_DISPLAY',
+ 'android.permission.COPY_PROTECTED_DATA',
+ 'android.permission.CREATE_USERS',
+ 'android.permission.CRYPT_KEEPER',
+ 'android.permission.DELETE_CACHE_FILES',
+ 'android.permission.DELETE_PACKAGES',
+ 'android.permission.DEVICE_POWER',
+ 'android.permission.DIAGNOSTIC',
+ 'android.permission.DISABLE_KEYGUARD',
+ 'android.permission.DISPATCH_NFC_MESSAGE',
+ 'android.permission.DISPATCH_PROVISIONING_MESSAGE',
+ 'android.permission.DOWNLOAD_CACHE_NON_PURGEABLE',
+ 'android.permission.DUMP',
+ 'android.permission.DVB_DEVICE',
+ 'android.permission.EXPAND_STATUS_BAR',
+ 'android.permission.FACTORY_TEST',
+ 'android.permission.FILTER_EVENTS',
+ 'android.permission.FLASHLIGHT',
+ 'android.permission.FORCE_BACK',
+ 'android.permission.FORCE_STOP_PACKAGES',
+ 'android.permission.FOREGROUND_SERVICE',
+ 'android.permission.FOREGROUND_SERVICE_CAMERA',
+ 'android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE',
+ 'android.permission.FOREGROUND_SERVICE_DATA_SYNC',
+ 'android.permission.FOREGROUND_SERVICE_HEALTH',
+ 'android.permission.FOREGROUND_SERVICE_LOCATION',
+ 'android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK',
+ 'android.permission.FOREGROUND_SERVICE_MICROPHONE',
+ 'android.permission.FOREGROUND_SERVICE_PHONE_CALL',
+ 'android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING',
+ 'android.permission.FRAME_STATS',
+ 'android.permission.FREEZE_SCREEN',
+ 'android.permission.GET_ACCOUNTS',
+ 'android.permission.GET_ACCOUNTS_PRIVILEGED',
+ 'android.permission.GET_APP_GRANTED_URI_PERMISSIONS',
+ 'android.permission.GET_APP_OPS_STATS',
+ 'android.permission.GET_DETAILED_TASKS',
+ 'android.permission.GET_INTENT_SENDER_INTENT',
+ 'android.permission.GET_PACKAGE_IMPORTANCE',
+ 'android.permission.GET_PACKAGE_SIZE',
+ 'android.permission.GET_PASSWORD',
+ 'android.permission.GET_PROCESS_STATE_AND_OOM_SCORE',
+ 'android.permission.GET_TASKS',
+ 'android.permission.GET_TOP_ACTIVITY_INFO',
+ 'android.permission.GLOBAL_SEARCH',
+ 'android.permission.GLOBAL_SEARCH_CONTROL',
+ 'android.permission.GRANT_RUNTIME_PERMISSIONS',
+ 'android.permission.HARDWARE_TEST',
+ 'android.permission.HDMI_CEC',
+ 'android.permission.INJECT_EVENTS',
+ 'android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS',
+ 'android.permission.INSTALL_LOCATION_PROVIDER',
+ 'android.permission.INSTALL_PACKAGES',
+ 'android.permission.INTENT_FILTER_VERIFICATION_AGENT',
+ 'android.permission.INTERACT_ACROSS_USERS',
+ 'android.permission.INTERACT_ACROSS_USERS_FULL',
+ 'android.permission.INTERNAL_SYSTEM_WINDOW',
+ 'android.permission.INTERNET',
+ 'android.permission.INVOKE_CARRIER_SETUP',
+ 'android.permission.KILL_BACKGROUND_PROCESSES',
+ 'android.permission.KILL_UID',
+ 'android.permission.LAUNCH_TRUST_AGENT_SETTINGS',
+ 'android.permission.LOCAL_MAC_ADDRESS',
+ 'android.permission.LOCATION_HARDWARE',
+ 'android.permission.LOOP_RADIO',
+ 'android.permission.MANAGE_ACCOUNTS',
+ 'android.permission.MANAGE_ACTIVITY_STACKS',
+ 'android.permission.MANAGE_APP_OPS_RESTRICTIONS',
+ 'android.permission.MANAGE_APP_TOKENS',
+ 'android.permission.MANAGE_CA_CERTIFICATES',
+ 'android.permission.MANAGE_DEVICE_ADMINS',
+ 'android.permission.MANAGE_DOCUMENTS',
+ 'android.permission.MANAGE_EXTERNAL_STORAGE',
+ 'android.permission.MANAGE_FINGERPRINT',
+ 'android.permission.MANAGE_MEDIA_PROJECTION',
+ 'android.permission.MANAGE_NETWORK_POLICY',
+ 'android.permission.MANAGE_NOTIFICATIONS',
+ 'android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS',
+ 'android.permission.MANAGE_SOUND_TRIGGER',
+ 'android.permission.MANAGE_USB',
+ 'android.permission.MANAGE_USERS',
+ 'android.permission.MANAGE_VOICE_KEYPHRASES',
+ 'android.permission.MASTER_CLEAR',
+ 'android.permission.MEDIA_CONTENT_CONTROL',
+ 'android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS',
+ 'android.permission.MODIFY_AUDIO_ROUTING',
+ 'android.permission.MODIFY_AUDIO_SETTINGS',
+ 'android.permission.MODIFY_CELL_BROADCASTS',
+ 'android.permission.MODIFY_DAY_NIGHT_MODE',
+ 'android.permission.MODIFY_NETWORK_ACCOUNTING',
+ 'android.permission.MODIFY_PARENTAL_CONTROLS',
+ 'android.permission.MODIFY_PHONE_STATE',
+ 'android.permission.MOUNT_FORMAT_FILESYSTEMS',
+ 'android.permission.MOUNT_UNMOUNT_FILESYSTEMS',
+ 'android.permission.MOVE_PACKAGE',
+ 'android.permission.NEARBY_WIFI_DEVICES',
+ 'android.permission.NET_ADMIN',
+ 'android.permission.NET_TUNNELING',
+ 'android.permission.NFC',
+ 'android.permission.NFC_HANDOVER_STATUS',
+ 'android.permission.NFC_TRANSACTION_EVENT',
+ 'android.permission.NOTIFICATIONS',
+ 'android.permission.NOTIFY_PENDING_SYSTEM_UPDATE',
+ 'android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS',
+ 'android.permission.OEM_UNLOCK_STATE',
+ 'android.permission.OVERRIDE_WIFI_CONFIG',
+ 'android.permission.PACKAGE_USAGE_STATS',
+ 'android.permission.PACKAGE_VERIFICATION_AGENT',
+ 'android.permission.PACKET_KEEPALIVE_OFFLOAD',
+ 'android.permission.PEERS_MAC_ADDRESS',
+ 'android.permission.PERFORM_CDMA_PROVISIONING',
+ 'android.permission.PERFORM_SIM_ACTIVATION',
+ 'android.permission.PERSISTENT_ACTIVITY',
+ 'android.permission.PROCESS_CALLLOG_INFO',
+ 'android.permission.PROCESS_OUTGOING_CALLS',
+ 'android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION',
+ 'android.permission.PROVIDE_TRUST_AGENT',
+ 'android.permission.QUERY_ALL_PACKAGES',
+ 'android.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT',
+ 'android.permission.READ_BLOCKED_NUMBERS',
+ 'android.permission.READ_CALENDAR',
+ 'android.permission.READ_CALL_LOG',
+ 'android.permission.READ_CONTACTS',
+ 'android.permission.READ_DREAM_STATE',
+ 'android.permission.READ_EXTERNAL_STORAGE',
+ 'android.permission.READ_FRAME_BUFFER',
+ 'android.permission.READ_INPUT_STATE',
+ 'android.permission.READ_INSTALL_SESSIONS',
+ 'android.permission.READ_LOGS',
+ 'android.permission.READ_MEDIA_AUDIO',
+ 'android.permission.READ_MEDIA_IMAGES',
+ 'android.permission.READ_MEDIA_VIDEO',
+ 'android.permission.READ_MEDIA_VISUAL_USER_SELECTED',
+ 'android.permission.READ_NETWORK_USAGE_HISTORY',
+ 'android.permission.READ_OEM_UNLOCK_STATE',
+ 'android.permission.READ_PHONE_NUMBERS',
+ 'android.permission.READ_PRECISE_PHONE_STATE',
+ 'android.permission.READ_PRIVILEGED_PHONE_STATE',
+ 'android.permission.READ_PROFILE',
+ 'android.permission.READ_SEARCH_INDEXABLES',
+ 'android.permission.READ_SMS',
+ 'android.permission.READ_SOCIAL_STREAM',
+ 'android.permission.READ_SYNC_SETTINGS',
+ 'android.permission.READ_SYNC_STATS',
+ 'android.permission.READ_USER_DICTIONARY',
+ 'android.permission.READ_WIFI_CREDENTIAL',
+ 'android.permission.REAL_GET_TASKS',
+ 'android.permission.REBOOT',
+ 'android.permission.RECEIVE_BLUETOOTH_MAP',
+ 'android.permission.RECEIVE_BOOT_COMPLETED',
+ 'android.permission.RECEIVE_DATA_ACTIVITY_CHANGE',
+ 'android.permission.RECEIVE_EMERGENCY_BROADCAST',
+ 'android.permission.RECEIVE_MEDIA_RESOURCE_USAGE',
+ 'android.permission.RECEIVE_MMS',
+ 'android.permission.RECEIVE_SMS',
+ 'android.permission.RECEIVE_STK_COMMANDS',
+ 'android.permission.RECEIVE_WAP_PUSH',
+ 'android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE',
+ 'android.permission.RECOVERY',
+ 'android.permission.RECORD_AUDIO',
+ 'android.permission.REGISTER_CALL_PROVIDER',
+ 'android.permission.REGISTER_CONNECTION_MANAGER',
+ 'android.permission.REGISTER_SIM_SUBSCRIPTION',
+ 'android.permission.REGISTER_WINDOW_MANAGER_LISTENERS',
+ 'android.permission.REMOTE_AUDIO_PLAYBACK',
+ 'android.permission.REMOVE_DRM_CERTIFICATES',
+ 'android.permission.REMOVE_TASKS',
+ 'android.permission.REORDER_TASKS',
+ 'android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS',
+ 'android.permission.REQUEST_INSTALL_PACKAGES',
+ 'android.permission.RESET_FINGERPRINT_LOCKOUT',
+ 'android.permission.RESET_SHORTCUT_MANAGER_THROTTLING',
+ 'android.permission.RESTART_PACKAGES',
+ 'android.permission.RETRIEVE_WINDOW_CONTENT',
+ 'android.permission.RETRIEVE_WINDOW_TOKEN',
+ 'android.permission.REVOKE_RUNTIME_PERMISSIONS',
+ 'android.permission.SCORE_NETWORKS',
+ 'android.permission.SCHEDULE_EXACT_ALARM',
+ 'android.permission.SEND_CALL_LOG_CHANGE',
+ 'android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS',
+ 'android.permission.SEND_RESPOND_VIA_MESSAGE',
+ 'android.permission.SEND_SMS',
+ 'android.permission.SEND_SMS_NO_CONFIRMATION',
+ 'android.permission.SERIAL_PORT',
+ 'android.permission.SET_ACTIVITY_WATCHER',
+ 'android.permission.SET_ALWAYS_FINISH',
+ 'android.permission.SET_ANIMATION_SCALE',
+ 'android.permission.SET_DEBUG_APP',
+ 'android.permission.SET_INPUT_CALIBRATION',
+ 'android.permission.SET_KEYBOARD_LAYOUT',
+ 'android.permission.SET_ORIENTATION',
+ 'android.permission.SET_POINTER_SPEED',
+ 'android.permission.SET_PREFERRED_APPLICATIONS',
+ 'android.permission.SET_PROCESS_LIMIT',
+ 'android.permission.SET_SCREEN_COMPATIBILITY',
+ 'android.permission.SET_TIME',
+ 'android.permission.SET_TIME_ZONE',
+ 'android.permission.SET_WALLPAPER',
+ 'android.permission.SET_WALLPAPER_COMPONENT',
+ 'android.permission.SET_WALLPAPER_HINTS',
+ 'android.permission.SHUTDOWN',
+ 'android.permission.SIGNAL_PERSISTENT_PROCESSES',
+ 'android.permission.START_ANY_ACTIVITY',
+ 'android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY',
+ 'android.permission.START_TASKS_FROM_RECENTS',
+ 'android.permission.STATUS_BAR',
+ 'android.permission.STATUS_BAR_SERVICE',
+ 'android.permission.STOP_APP_SWITCHES',
+ 'android.permission.STORAGE_INTERNAL',
+ 'android.permission.SUBSCRIBED_FEEDS_READ',
+ 'android.permission.SUBSCRIBED_FEEDS_WRITE',
+ 'android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME',
+ 'android.permission.SYSTEM_ALERT_WINDOW',
+ 'android.permission.TABLET_MODE',
+ 'android.permission.TEMPORARY_ENABLE_ACCESSIBILITY',
+ 'android.permission.TETHER_PRIVILEGED',
+ 'android.permission.TRANSMIT_IR',
+ 'android.permission.TRUST_LISTENER',
+ 'android.permission.TV_INPUT_HARDWARE',
+ 'android.permission.TV_VIRTUAL_REMOTE_CONTROLLER',
+ 'android.permission.UPDATE_APP_OPS_STATS',
+ 'android.permission.UPDATE_CONFIG',
+ 'android.permission.UPDATE_DEVICE_STATS',
+ 'android.permission.UPDATE_LOCK',
+ 'android.permission.UPDATE_LOCK_TASK_PACKAGES',
+ 'android.permission.USER_ACTIVITY',
+ 'android.permission.USE_BIOMETRIC',
+ 'android.permission.USE_CREDENTIALS',
+ 'android.permission.USE_FINGERPRINT',
+ 'android.permission.USE_FULL_SCREEN_INTENT',
+ 'android.permission.USE_SIP',
+ 'android.permission.VIBRATE',
+ 'android.permission.WAKE_LOCK',
+ 'android.permission.WRITE_APN_SETTINGS',
+ 'android.permission.WRITE_BLOCKED_NUMBERS',
+ 'android.permission.WRITE_CALENDAR',
+ 'android.permission.WRITE_CALL_LOG',
+ 'android.permission.WRITE_CONTACTS',
+ 'android.permission.WRITE_DREAM_STATE',
+ 'android.permission.WRITE_EXTERNAL_STORAGE',
+ 'android.permission.WRITE_GSERVICES',
+ 'android.permission.WRITE_MEDIA_STORAGE',
+ 'android.permission.WRITE_PROFILE',
+ 'android.permission.WRITE_SECURE_SETTINGS',
+ 'android.permission.WRITE_SETTINGS',
+ 'android.permission.WRITE_SMS',
+ 'android.permission.WRITE_SOCIAL_STREAM',
+ 'android.permission.WRITE_SYNC_SETTINGS',
+ 'android.permission.WRITE_USER_DICTIONARY',
],
googleServicesFile: './google-services.json',
useNextNotificationsApi: true,
diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
index 6ee54da..41e3084 100644
--- a/app/(tabs)/_layout.tsx
+++ b/app/(tabs)/_layout.tsx
@@ -44,6 +44,13 @@ export default function TabLayout() {
tabBarIcon: ({ color }: { color: string }) => ,
}}
/>
+ ,
+ }}
+ />
);
}
diff --git a/app/(tabs)/permissions/camera-mic.tsx b/app/(tabs)/permissions/camera-mic.tsx
new file mode 100644
index 0000000..89d846f
--- /dev/null
+++ b/app/(tabs)/permissions/camera-mic.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+import CameraMicrophonePermissionDemo from '@/components/permissions/CameraMicrophonePermissionDemo';
+
+export default function CameraMicScreen() {
+ return (
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+});
+
diff --git a/app/(tabs)/permissions/connectivity.tsx b/app/(tabs)/permissions/connectivity.tsx
new file mode 100644
index 0000000..e2e4539
--- /dev/null
+++ b/app/(tabs)/permissions/connectivity.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+import BluetoothNearbyPermissionDemo from '@/components/permissions/BluetoothNearbyPermissionDemo';
+
+export default function ConnectivityScreen() {
+ return (
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+});
+
diff --git a/app/(tabs)/permissions/index.tsx b/app/(tabs)/permissions/index.tsx
new file mode 100644
index 0000000..a58330f
--- /dev/null
+++ b/app/(tabs)/permissions/index.tsx
@@ -0,0 +1,60 @@
+import { Link } from 'expo-router';
+import React from 'react';
+import { View, Text, StyleSheet, ScrollView, Pressable } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+
+const routes = [
+ { href: '/permissions/location', title: 'Location (foreground/background)' },
+ { href: '/permissions/camera-mic', title: 'Camera & Microphone' },
+ { href: '/permissions/notifications', title: 'Notifications' },
+ { href: '/permissions/media-storage', title: 'Media Library' },
+ { href: '/permissions/storage', title: 'Storage & File Access' },
+ { href: '/permissions/telephony-sms', title: 'Telephony & SMS' },
+ { href: '/permissions/connectivity', title: 'Bluetooth & Nearby' },
+];
+
+export default function PermissionsHub() {
+ return (
+
+
+
+
+ Explore Android permission demos. Each link opens a focused screen that requests the associated runtime permissions and
+ performs a small capability check.
+
+ {routes.map((route) => (
+
+ {route.title}
+
+
+ Open demo
+
+
+
+ ))}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ lead: { color: '#ccc', fontSize: 14, lineHeight: 20, marginBottom: 6 },
+ card: {
+ backgroundColor: '#111',
+ padding: 16,
+ borderRadius: 10,
+ gap: 8,
+ borderWidth: 1,
+ borderColor: '#222',
+ },
+ cardTitle: { color: '#fff', fontSize: 16, fontWeight: '600' },
+ button: {
+ backgroundColor: '#1e88e5',
+ paddingVertical: 10,
+ borderRadius: 8,
+ alignItems: 'center',
+ },
+ buttonText: { color: '#fff', fontWeight: '600' },
+});
diff --git a/app/(tabs)/permissions/location.tsx b/app/(tabs)/permissions/location.tsx
new file mode 100644
index 0000000..ded8ccb
--- /dev/null
+++ b/app/(tabs)/permissions/location.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+import LocationPermissionDemo from '@/components/permissions/LocationPermissionDemo';
+
+export default function LocationScreen() {
+ return (
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+});
+
diff --git a/app/(tabs)/permissions/media-storage.tsx b/app/(tabs)/permissions/media-storage.tsx
new file mode 100644
index 0000000..c6b860c
--- /dev/null
+++ b/app/(tabs)/permissions/media-storage.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+import MediaLibraryPermissionDemo from '@/components/permissions/MediaLibraryPermissionDemo';
+
+export default function MediaStorageScreen() {
+ return (
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+});
+
diff --git a/app/(tabs)/permissions/notifications.tsx b/app/(tabs)/permissions/notifications.tsx
new file mode 100644
index 0000000..37d97c6
--- /dev/null
+++ b/app/(tabs)/permissions/notifications.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+import NotificationsPermissionDemo from '@/components/permissions/NotificationsPermissionDemo';
+
+export default function NotificationsScreen() {
+ return (
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+});
+
diff --git a/app/(tabs)/permissions/storage.tsx b/app/(tabs)/permissions/storage.tsx
new file mode 100644
index 0000000..7988c5a
--- /dev/null
+++ b/app/(tabs)/permissions/storage.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+import StoragePermissionDemo from '@/components/permissions/StoragePermissionDemo';
+
+export default function StorageScreen() {
+ return (
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+});
+
diff --git a/app/(tabs)/permissions/telephony-sms.tsx b/app/(tabs)/permissions/telephony-sms.tsx
new file mode 100644
index 0000000..c424c38
--- /dev/null
+++ b/app/(tabs)/permissions/telephony-sms.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import CustomHeader from '@/components/CustomHeader';
+import TelephonySmsPermissionDemo from '@/components/permissions/TelephonySmsPermissionDemo';
+
+export default function TelephonySmsScreen() {
+ return (
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+});
+
diff --git a/assets/permissions-hub.png b/assets/permissions-hub.png
new file mode 100644
index 0000000000000000000000000000000000000000..0f336278b2d1405e76a598ca81146148f9490803
GIT binary patch
literal 25807
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
Vdd55MI`Y+ODq7gQe_Xxwe*hF^jV1s9
literal 0
HcmV?d00001
diff --git a/components/permissions/BluetoothNearbyPermissionDemo.tsx b/components/permissions/BluetoothNearbyPermissionDemo.tsx
new file mode 100644
index 0000000..311bda0
--- /dev/null
+++ b/components/permissions/BluetoothNearbyPermissionDemo.tsx
@@ -0,0 +1,55 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, ScrollView, PermissionsAndroid, Platform } from 'react-native';
+
+const REQUESTS = [
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_ADVERTISE,
+ PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
+ PermissionsAndroid.PERMISSIONS.NEARBY_WIFI_DEVICES,
+];
+
+export default function BluetoothNearbyPermissionDemo() {
+ const [statuses, setStatuses] = useState>({});
+
+ const request = async () => {
+ if (Platform.OS !== 'android') {
+ setStatuses({ platform: 'Only relevant on Android' });
+ return;
+ }
+ const results = await PermissionsAndroid.requestMultiple(REQUESTS);
+ setStatuses(results);
+ };
+
+ return (
+
+ Bluetooth & Nearby
+
+ Requests BLUETOOTH_CONNECT / SCAN / ADVERTISE along with NEARBY_WIFI_DEVICES and fine location to showcase nearby device
+ discovery prerequisites.
+
+
+
+ {Object.keys(statuses).length === 0 ? (
+ No results yet
+ ) : (
+ Object.entries(statuses).map(([key, value]) => (
+
+ {key.split('.').pop()}: {value}
+
+ ))
+ )}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ title: { color: '#fff', fontSize: 18, fontWeight: '700' },
+ copy: { color: '#ccc', fontSize: 14, lineHeight: 20 },
+ statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
+ statusText: { color: '#fff', marginBottom: 4 },
+});
+
diff --git a/components/permissions/CameraMicrophonePermissionDemo.tsx b/components/permissions/CameraMicrophonePermissionDemo.tsx
new file mode 100644
index 0000000..2d87548
--- /dev/null
+++ b/components/permissions/CameraMicrophonePermissionDemo.tsx
@@ -0,0 +1,46 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, ScrollView } from 'react-native';
+import { Camera } from 'expo-camera';
+
+export default function CameraMicrophonePermissionDemo() {
+ const [cameraStatus, setCameraStatus] = useState('unknown');
+ const [micStatus, setMicStatus] = useState('unknown');
+ const [availableTypes, setAvailableTypes] = useState('not queried');
+
+ const requestPermissions = async () => {
+ const camera = await Camera.requestCameraPermissionsAsync();
+ const mic = await Camera.requestMicrophonePermissionsAsync();
+ setCameraStatus(camera.status);
+ setMicStatus(mic.status);
+
+ if (camera.status === 'granted') {
+ const types = await Camera.getAvailableCameraTypesAsync();
+ setAvailableTypes(types.join(', ') || 'none reported');
+ }
+ };
+
+ return (
+
+ Camera & Microphone
+
+ Requests CAMERA and RECORD_AUDIO plus microphone access via expo-camera. Queries available camera types once granted.
+
+
+
+ Camera: {cameraStatus}
+ Microphone: {micStatus}
+ Available cameras: {availableTypes}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ title: { color: '#fff', fontSize: 18, fontWeight: '700' },
+ copy: { color: '#ccc', fontSize: 14, lineHeight: 20 },
+ statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
+ statusText: { color: '#fff', marginBottom: 4 },
+});
+
diff --git a/components/permissions/LocationPermissionDemo.tsx b/components/permissions/LocationPermissionDemo.tsx
new file mode 100644
index 0000000..507773c
--- /dev/null
+++ b/components/permissions/LocationPermissionDemo.tsx
@@ -0,0 +1,63 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, ScrollView, Platform } from 'react-native';
+import * as Location from 'expo-location';
+
+export default function LocationPermissionDemo() {
+ const [status, setStatus] = useState(null);
+ const [backgroundStatus, setBackgroundStatus] = useState(null);
+ const [coords, setCoords] = useState('');
+ const [error, setError] = useState('');
+
+ const requestPermissions = async () => {
+ setError('');
+ const fg = await Location.requestForegroundPermissionsAsync();
+ setStatus(fg.status);
+
+ if (Platform.OS === 'android') {
+ const bg = await Location.requestBackgroundPermissionsAsync();
+ setBackgroundStatus(bg.status);
+ }
+ };
+
+ const fetchLocation = async () => {
+ try {
+ const loc = await Location.getCurrentPositionAsync({});
+ setCoords(`${loc.coords.latitude.toFixed(5)}, ${loc.coords.longitude.toFixed(5)}`);
+ } catch (e) {
+ setError((e as Error).message);
+ }
+ };
+
+ return (
+
+ Location (foreground & background)
+
+ Requests ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_BACKGROUND_LOCATION and demonstrates fetching a single
+ location fix via expo-location.
+
+
+
+
+
+
+
+ Foreground: {status ?? 'unknown'}
+ {Platform.OS === 'android' && Background: {backgroundStatus ?? 'unknown'}}
+ {coords ? Last fix: {coords} : null}
+ {error ? {error} : null}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ title: { color: '#fff', fontSize: 18, fontWeight: '700' },
+ copy: { color: '#ccc', fontSize: 14, lineHeight: 20 },
+ statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
+ statusText: { color: '#fff', marginBottom: 4 },
+ error: { color: '#ff6b6b' },
+ gap: { height: 10 },
+});
+
diff --git a/components/permissions/MediaLibraryPermissionDemo.tsx b/components/permissions/MediaLibraryPermissionDemo.tsx
new file mode 100644
index 0000000..332474a
--- /dev/null
+++ b/components/permissions/MediaLibraryPermissionDemo.tsx
@@ -0,0 +1,47 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, ScrollView } from 'react-native';
+import * as MediaLibrary from 'expo-media-library';
+
+export default function MediaLibraryPermissionDemo() {
+ const [status, setStatus] = useState('unknown');
+ const [assetSummary, setAssetSummary] = useState('Not loaded');
+
+ const requestPermissions = async () => {
+ const permissions = await MediaLibrary.requestPermissionsAsync(true);
+ setStatus(permissions.status);
+ };
+
+ const loadAssets = async () => {
+ const assets = await MediaLibrary.getAssetsAsync({ first: 5, sortBy: MediaLibrary.SortBy.modificationTime });
+ setAssetSummary(`Fetched ${assets.assets.length} of ${assets.totalCount} assets`);
+ };
+
+ return (
+
+ Media & Storage
+
+ Requests READ_MEDIA_* / ACCESS_MEDIA_LOCATION style permissions and fetches a small sample of media entries from the
+ device library.
+
+
+
+
+
+
+ Status: {status}
+ {assetSummary}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ title: { color: '#fff', fontSize: 18, fontWeight: '700' },
+ copy: { color: '#ccc', fontSize: 14, lineHeight: 20 },
+ statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
+ statusText: { color: '#fff', marginBottom: 4 },
+ gap: { height: 10 },
+});
+
diff --git a/components/permissions/NotificationsPermissionDemo.tsx b/components/permissions/NotificationsPermissionDemo.tsx
new file mode 100644
index 0000000..63ac9f0
--- /dev/null
+++ b/components/permissions/NotificationsPermissionDemo.tsx
@@ -0,0 +1,52 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, ScrollView } from 'react-native';
+import * as Notifications from 'expo-notifications';
+
+export default function NotificationsPermissionDemo() {
+ const [status, setStatus] = useState('unknown');
+ const [lastScheduledId, setLastScheduledId] = useState('');
+
+ const requestPermissions = async () => {
+ const settings = await Notifications.requestPermissionsAsync();
+ setStatus(settings.status ?? settings.granted ? 'granted' : 'denied');
+ };
+
+ const schedule = async () => {
+ const id = await Notifications.scheduleNotificationAsync({
+ content: {
+ title: 'Permission demo',
+ body: 'Local notification demonstrating POST_NOTIFICATIONS / NOTIFICATIONS usage.',
+ },
+ trigger: { seconds: 2 },
+ });
+ setLastScheduledId(id);
+ };
+
+ return (
+
+ Notifications
+
+ Requests NOTIFICATIONS / POST_NOTIFICATIONS and schedules a sample local notification through expo-notifications.
+
+
+
+
+
+
+ Status: {status}
+ {lastScheduledId ? Last scheduled id: {lastScheduledId} : null}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ title: { color: '#fff', fontSize: 18, fontWeight: '700' },
+ copy: { color: '#ccc', fontSize: 14, lineHeight: 20 },
+ statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
+ statusText: { color: '#fff', marginBottom: 4 },
+ gap: { height: 10 },
+});
+
diff --git a/components/permissions/StoragePermissionDemo.tsx b/components/permissions/StoragePermissionDemo.tsx
new file mode 100644
index 0000000..6b38a83
--- /dev/null
+++ b/components/permissions/StoragePermissionDemo.tsx
@@ -0,0 +1,56 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, ScrollView, PermissionsAndroid, Platform } from 'react-native';
+
+const REQUESTS = [
+ PermissionsAndroid.PERMISSIONS.MANAGE_EXTERNAL_STORAGE,
+ PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
+ PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
+ PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES,
+ PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO,
+ PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO,
+];
+
+export default function StoragePermissionDemo() {
+ const [statuses, setStatuses] = useState>({});
+
+ const request = async () => {
+ if (Platform.OS !== 'android') {
+ setStatuses({ platform: 'Only relevant on Android' });
+ return;
+ }
+ const results = await PermissionsAndroid.requestMultiple(REQUESTS);
+ setStatuses(results);
+ };
+
+ return (
+
+ Storage & File Access
+
+ Requests MANAGE_EXTERNAL_STORAGE plus legacy READ/WRITE_EXTERNAL_STORAGE and modern READ_MEDIA_* runtime permissions to
+ illustrate storage access flows.
+
+
+
+ {Object.keys(statuses).length === 0 ? (
+ No results yet
+ ) : (
+ Object.entries(statuses).map(([key, value]) => (
+
+ {key.split('.').pop()}: {value}
+
+ ))
+ )}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ title: { color: '#fff', fontSize: 18, fontWeight: '700' },
+ copy: { color: '#ccc', fontSize: 14, lineHeight: 20 },
+ statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
+ statusText: { color: '#fff', marginBottom: 4 },
+});
+
diff --git a/components/permissions/TelephonySmsPermissionDemo.tsx b/components/permissions/TelephonySmsPermissionDemo.tsx
new file mode 100644
index 0000000..a267674
--- /dev/null
+++ b/components/permissions/TelephonySmsPermissionDemo.tsx
@@ -0,0 +1,57 @@
+import React, { useState } from 'react';
+import { View, Text, Button, StyleSheet, ScrollView, PermissionsAndroid, Platform } from 'react-native';
+
+const REQUESTS = [
+ PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE,
+ PermissionsAndroid.PERMISSIONS.READ_PHONE_NUMBERS,
+ PermissionsAndroid.PERMISSIONS.READ_SMS,
+ PermissionsAndroid.PERMISSIONS.SEND_SMS,
+ PermissionsAndroid.PERMISSIONS.CALL_PHONE,
+ PermissionsAndroid.PERMISSIONS.ANSWER_PHONE_CALLS,
+ PermissionsAndroid.PERMISSIONS.PROCESS_OUTGOING_CALLS,
+];
+
+export default function TelephonySmsPermissionDemo() {
+ const [statuses, setStatuses] = useState>({});
+
+ const request = async () => {
+ if (Platform.OS !== 'android') {
+ setStatuses({ platform: 'Only relevant on Android' });
+ return;
+ }
+ const results = await PermissionsAndroid.requestMultiple(REQUESTS);
+ setStatuses(results);
+ };
+
+ return (
+
+ Telephony & SMS
+
+ Requests READ_PHONE_STATE, READ_PHONE_NUMBERS, CALL_PHONE, SEND_SMS, ANSWER_PHONE_CALLS, and PROCESS_OUTGOING_CALLS. These
+ permissions are sensitive and may require additional Play Store declarations.
+
+
+
+ {Object.keys(statuses).length === 0 ? (
+ No results yet
+ ) : (
+ Object.entries(statuses).map(([key, value]) => (
+
+ {key.split('.').pop()}: {value}
+
+ ))
+ )}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#000' },
+ content: { padding: 16, gap: 12 },
+ title: { color: '#fff', fontSize: 18, fontWeight: '700' },
+ copy: { color: '#ccc', fontSize: 14, lineHeight: 20 },
+ statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
+ statusText: { color: '#fff', marginBottom: 4 },
+});
+
diff --git a/version.json b/version.json
index ff9a2dd..3f7a1a1 100644
--- a/version.json
+++ b/version.json
@@ -1,5 +1,5 @@
{
- "version": "1.0.68",
- "iosBuildNumber": "68",
- "androidVersionCode": 68
+ "version": "1.0.69",
+ "iosBuildNumber": "69",
+ "androidVersionCode": 69
}
\ No newline at end of file
From 70d5883e6ba71faf0d1be491d2a4203dca29d1c6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 1 Jan 2026 10:15:56 +0000
Subject: [PATCH 4/5] Polish permission demos
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
---
app/(tabs)/permissions/camera-mic.tsx | 1 -
app/(tabs)/permissions/connectivity.tsx | 1 -
app/(tabs)/permissions/location.tsx | 1 -
app/(tabs)/permissions/media-storage.tsx | 1 -
app/(tabs)/permissions/notifications.tsx | 1 -
app/(tabs)/permissions/storage.tsx | 1 -
app/(tabs)/permissions/telephony-sms.tsx | 1 -
components/permissions/BluetoothNearbyPermissionDemo.tsx | 1 -
components/permissions/CameraMicrophonePermissionDemo.tsx | 1 -
components/permissions/LocationPermissionDemo.tsx | 1 -
components/permissions/MediaLibraryPermissionDemo.tsx | 1 -
components/permissions/NotificationsPermissionDemo.tsx | 4 ++--
components/permissions/StoragePermissionDemo.tsx | 1 -
components/permissions/TelephonySmsPermissionDemo.tsx | 1 -
14 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/app/(tabs)/permissions/camera-mic.tsx b/app/(tabs)/permissions/camera-mic.tsx
index 89d846f..27779ab 100644
--- a/app/(tabs)/permissions/camera-mic.tsx
+++ b/app/(tabs)/permissions/camera-mic.tsx
@@ -15,4 +15,3 @@ export default function CameraMicScreen() {
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
});
-
diff --git a/app/(tabs)/permissions/connectivity.tsx b/app/(tabs)/permissions/connectivity.tsx
index e2e4539..fedd0f4 100644
--- a/app/(tabs)/permissions/connectivity.tsx
+++ b/app/(tabs)/permissions/connectivity.tsx
@@ -15,4 +15,3 @@ export default function ConnectivityScreen() {
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
});
-
diff --git a/app/(tabs)/permissions/location.tsx b/app/(tabs)/permissions/location.tsx
index ded8ccb..c9d3855 100644
--- a/app/(tabs)/permissions/location.tsx
+++ b/app/(tabs)/permissions/location.tsx
@@ -15,4 +15,3 @@ export default function LocationScreen() {
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
});
-
diff --git a/app/(tabs)/permissions/media-storage.tsx b/app/(tabs)/permissions/media-storage.tsx
index c6b860c..5a41d0e 100644
--- a/app/(tabs)/permissions/media-storage.tsx
+++ b/app/(tabs)/permissions/media-storage.tsx
@@ -15,4 +15,3 @@ export default function MediaStorageScreen() {
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
});
-
diff --git a/app/(tabs)/permissions/notifications.tsx b/app/(tabs)/permissions/notifications.tsx
index 37d97c6..cd61eae 100644
--- a/app/(tabs)/permissions/notifications.tsx
+++ b/app/(tabs)/permissions/notifications.tsx
@@ -15,4 +15,3 @@ export default function NotificationsScreen() {
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
});
-
diff --git a/app/(tabs)/permissions/storage.tsx b/app/(tabs)/permissions/storage.tsx
index 7988c5a..f0b5ce3 100644
--- a/app/(tabs)/permissions/storage.tsx
+++ b/app/(tabs)/permissions/storage.tsx
@@ -15,4 +15,3 @@ export default function StorageScreen() {
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
});
-
diff --git a/app/(tabs)/permissions/telephony-sms.tsx b/app/(tabs)/permissions/telephony-sms.tsx
index c424c38..dcd722b 100644
--- a/app/(tabs)/permissions/telephony-sms.tsx
+++ b/app/(tabs)/permissions/telephony-sms.tsx
@@ -15,4 +15,3 @@ export default function TelephonySmsScreen() {
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
});
-
diff --git a/components/permissions/BluetoothNearbyPermissionDemo.tsx b/components/permissions/BluetoothNearbyPermissionDemo.tsx
index 311bda0..45a858d 100644
--- a/components/permissions/BluetoothNearbyPermissionDemo.tsx
+++ b/components/permissions/BluetoothNearbyPermissionDemo.tsx
@@ -52,4 +52,3 @@ const styles = StyleSheet.create({
statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
statusText: { color: '#fff', marginBottom: 4 },
});
-
diff --git a/components/permissions/CameraMicrophonePermissionDemo.tsx b/components/permissions/CameraMicrophonePermissionDemo.tsx
index 2d87548..d7aebf3 100644
--- a/components/permissions/CameraMicrophonePermissionDemo.tsx
+++ b/components/permissions/CameraMicrophonePermissionDemo.tsx
@@ -43,4 +43,3 @@ const styles = StyleSheet.create({
statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
statusText: { color: '#fff', marginBottom: 4 },
});
-
diff --git a/components/permissions/LocationPermissionDemo.tsx b/components/permissions/LocationPermissionDemo.tsx
index 507773c..e012158 100644
--- a/components/permissions/LocationPermissionDemo.tsx
+++ b/components/permissions/LocationPermissionDemo.tsx
@@ -60,4 +60,3 @@ const styles = StyleSheet.create({
error: { color: '#ff6b6b' },
gap: { height: 10 },
});
-
diff --git a/components/permissions/MediaLibraryPermissionDemo.tsx b/components/permissions/MediaLibraryPermissionDemo.tsx
index 332474a..ef506f6 100644
--- a/components/permissions/MediaLibraryPermissionDemo.tsx
+++ b/components/permissions/MediaLibraryPermissionDemo.tsx
@@ -44,4 +44,3 @@ const styles = StyleSheet.create({
statusText: { color: '#fff', marginBottom: 4 },
gap: { height: 10 },
});
-
diff --git a/components/permissions/NotificationsPermissionDemo.tsx b/components/permissions/NotificationsPermissionDemo.tsx
index 63ac9f0..d660ce2 100644
--- a/components/permissions/NotificationsPermissionDemo.tsx
+++ b/components/permissions/NotificationsPermissionDemo.tsx
@@ -8,7 +8,8 @@ export default function NotificationsPermissionDemo() {
const requestPermissions = async () => {
const settings = await Notifications.requestPermissionsAsync();
- setStatus(settings.status ?? settings.granted ? 'granted' : 'denied');
+ const derivedStatus = settings.status ?? (settings.granted ? 'granted' : 'denied');
+ setStatus(derivedStatus);
};
const schedule = async () => {
@@ -49,4 +50,3 @@ const styles = StyleSheet.create({
statusText: { color: '#fff', marginBottom: 4 },
gap: { height: 10 },
});
-
diff --git a/components/permissions/StoragePermissionDemo.tsx b/components/permissions/StoragePermissionDemo.tsx
index 6b38a83..3df8ee8 100644
--- a/components/permissions/StoragePermissionDemo.tsx
+++ b/components/permissions/StoragePermissionDemo.tsx
@@ -53,4 +53,3 @@ const styles = StyleSheet.create({
statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
statusText: { color: '#fff', marginBottom: 4 },
});
-
diff --git a/components/permissions/TelephonySmsPermissionDemo.tsx b/components/permissions/TelephonySmsPermissionDemo.tsx
index a267674..7ce005a 100644
--- a/components/permissions/TelephonySmsPermissionDemo.tsx
+++ b/components/permissions/TelephonySmsPermissionDemo.tsx
@@ -54,4 +54,3 @@ const styles = StyleSheet.create({
statusBox: { backgroundColor: '#111', padding: 12, borderRadius: 8, marginTop: 12 },
statusText: { color: '#fff', marginBottom: 4 },
});
-
From 624d6dc759367b481ba85dbcc02fdc641cd9aca9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 1 Jan 2026 10:16:54 +0000
Subject: [PATCH 5/5] Clarify permission handling
Co-authored-by: digitalnomad91 <2067771+digitalnomad91@users.noreply.github.com>
---
components/permissions/LocationPermissionDemo.tsx | 2 +-
components/permissions/NotificationsPermissionDemo.tsx | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/components/permissions/LocationPermissionDemo.tsx b/components/permissions/LocationPermissionDemo.tsx
index e012158..966b7f8 100644
--- a/components/permissions/LocationPermissionDemo.tsx
+++ b/components/permissions/LocationPermissionDemo.tsx
@@ -24,7 +24,7 @@ export default function LocationPermissionDemo() {
const loc = await Location.getCurrentPositionAsync({});
setCoords(`${loc.coords.latitude.toFixed(5)}, ${loc.coords.longitude.toFixed(5)}`);
} catch (e) {
- setError((e as Error).message);
+ setError(e instanceof Error ? e.message : String(e));
}
};
diff --git a/components/permissions/NotificationsPermissionDemo.tsx b/components/permissions/NotificationsPermissionDemo.tsx
index d660ce2..62fbfab 100644
--- a/components/permissions/NotificationsPermissionDemo.tsx
+++ b/components/permissions/NotificationsPermissionDemo.tsx
@@ -8,6 +8,7 @@ export default function NotificationsPermissionDemo() {
const requestPermissions = async () => {
const settings = await Notifications.requestPermissionsAsync();
+ // Expo returns both a status field and a legacy granted boolean; normalize to a single label for display.
const derivedStatus = settings.status ?? (settings.granted ? 'granted' : 'denied');
setStatus(derivedStatus);
};