{"id":6096,"date":"2026-04-16T14:57:44","date_gmt":"2026-04-16T14:57:44","guid":{"rendered":"https:\/\/stfcapital.org\/?page_id=6096"},"modified":"2026-04-16T14:57:44","modified_gmt":"2026-04-16T14:57:44","slug":"app-permissions","status":"publish","type":"page","link":"https:\/\/stfcapital.org\/index.php\/legal\/app-permissions\/","title":{"rendered":"App Permissions"},"content":{"rendered":"<p><!--\n  PERMISSIONS DISCLOSURE \u2014 paste the entire content below into a WordPress\n  \"Custom HTML\" block on a new Page.\n\n  Recommended page settings:\n    Title ..... App Permissions\n    Slug ...... permissions\n    Parent .... Legal\n--><\/p>\n<div class=\"stf-legal\">\n<div class=\"stf-hero\">\n    <span class=\"stf-eyebrow\">Document 02 of 04 \u00b7 Permissions<\/span><\/p>\n<h1 class=\"stf-hero-title\">Every permission the STF&nbsp;Capital app asks for, <em>and why<\/em>.<\/h1>\n<p class=\"stf-hero-lede\">\n      Android gives applications a powerful but explicit permission model: if the app<br \/>\n      wants to use your camera, read files from shared storage, deliver notifications<br \/>\n      or wake up after your phone reboots, it must declare that intention in its<br \/>\n      manifest and &mdash; for sensitive permissions &mdash; obtain your affirmative<br \/>\n      consent at runtime. This document is the authoritative, plain-English explanation<br \/>\n      of every permission STF Capital declares, why it is necessary, what the user<br \/>\n      experience looks like, and what happens if you choose not to grant it.\n    <\/p>\n<div class=\"stf-meta\">\n<div><strong>Version<\/strong> 1.0<\/div>\n<div><strong>Effective date<\/strong> 16 April 2026<\/div>\n<div><strong>Manifest scope<\/strong> <code>com.stfcapital.app<\/code><\/div>\n<div><strong>Target API level<\/strong> 36 (Android 14+)<\/div>\n<div><strong>Minimum API level<\/strong> 24 (Android 7.0)<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"stf-toc\">\n<div class=\"stf-toc-title\">On this page<\/div>\n<ol>\n<li><a href=\"#principles\">Principles we apply<\/a><\/li>\n<li><a href=\"#at-a-glance\">At a glance<\/a><\/li>\n<li><a href=\"#network\">Network &amp; connectivity<\/a><\/li>\n<li><a href=\"#camera\">Camera<\/a><\/li>\n<li><a href=\"#storage\">Media &amp; files<\/a><\/li>\n<li><a href=\"#biometric\">Biometric authentication<\/a><\/li>\n<li><a href=\"#notifications\">Notifications<\/a><\/li>\n<li><a href=\"#boot\">Boot &amp; scheduling<\/a><\/li>\n<li><a href=\"#vibrate\">Vibration<\/a><\/li>\n<li><a href=\"#not-requested\">What we do not request<\/a><\/li>\n<li><a href=\"#runtime-ux\">Runtime prompt experience<\/a><\/li>\n<li><a href=\"#revoke\">Revoking a permission<\/a><\/li>\n<li><a href=\"#android-versions\">How it differs by Android version<\/a><\/li>\n<li><a href=\"#play-review\">Google Play Permissions Review alignment<\/a><\/li>\n<li><a href=\"#decline\">What happens if you decline<\/a><\/li>\n<li><a href=\"#ios\">A note on iOS<\/a><\/li>\n<li><a href=\"#contact\">Questions<\/a><\/li>\n<\/ol><\/div>\n<h2 id=\"principles\">1. Principles we apply<\/h2>\n<p>Three principles govern every permission declaration in the STF Capital mobile application. Each was formally adopted at the architectural design stage and is reviewed before every new feature is shipped.<\/p>\n<ol>\n<li><strong>Necessity.<\/strong> We request a permission only when there is a concrete feature in the shipping app that cannot function without it. Speculative permissions (&ldquo;we might need it later&rdquo;) are never declared.<\/li>\n<li><strong>Least privilege.<\/strong> Where Android offers a less sensitive alternative for the same feature we prefer it. For example, we use the modern <code>READ_MEDIA_IMAGES<\/code> and <code>READ_MEDIA_VIDEO<\/code> permissions on Android&nbsp;13+ instead of the blanket <code>READ_EXTERNAL_STORAGE<\/code>.<\/li>\n<li><strong>Graceful degradation.<\/strong> If you deny a permission we request, the feature that needed it tells you so in a calm, non-nagging message and continues to offer whatever else the app can still do. You will not be locked out of the application because you declined a permission.<\/li>\n<\/ol>\n<h2 id=\"at-a-glance\">2. At a glance<\/h2>\n<p>The table below lists every permission declared in the application&rsquo;s <code>AndroidManifest.xml<\/code>. <span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span> permissions require a runtime prompt; <span class=\"stf-pill stf-pill--normal\">Normal<\/span> permissions are granted at install time; <span class=\"stf-pill stf-pill--optional\">Optional<\/span> entries are feature declarations rather than permissions.<\/p>\n<table class=\"stf-table\">\n<thead>\n<tr>\n<th>Permission<\/th>\n<th>Type<\/th>\n<th>Feature that uses it<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>INTERNET<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--normal\">Normal<\/span><\/td>\n<td>Talking to the Supabase backend; delivering push notifications<\/td>\n<\/tr>\n<tr>\n<td><code>ACCESS_NETWORK_STATE<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--normal\">Normal<\/span><\/td>\n<td>Detecting online\/offline state to queue work gracefully<\/td>\n<\/tr>\n<tr>\n<td><code>CAMERA<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span><\/td>\n<td>Photographing supporting documents and optional profile photo<\/td>\n<\/tr>\n<tr>\n<td><code>READ_MEDIA_IMAGES<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span><\/td>\n<td>Selecting document images from your photo library (Android 13+)<\/td>\n<\/tr>\n<tr>\n<td><code>READ_MEDIA_VIDEO<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span><\/td>\n<td>Selecting supporting video files (Android 13+)<\/td>\n<\/tr>\n<tr>\n<td><code>READ_EXTERNAL_STORAGE<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span><\/td>\n<td>Document selection on Android 12 and below only<\/td>\n<\/tr>\n<tr>\n<td><code>WRITE_EXTERNAL_STORAGE<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span><\/td>\n<td>Cached exports on Android 12 and below only<\/td>\n<\/tr>\n<tr>\n<td><code>USE_BIOMETRIC<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span><\/td>\n<td>Fingerprint\/face unlock after opt-in<\/td>\n<\/tr>\n<tr>\n<td><code>POST_NOTIFICATIONS<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--dangerous\">Dangerous<\/span><\/td>\n<td>Push and local notifications (Android 13+)<\/td>\n<\/tr>\n<tr>\n<td><code>VIBRATE<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--normal\">Normal<\/span><\/td>\n<td>Haptic feedback on notifications<\/td>\n<\/tr>\n<tr>\n<td><code>RECEIVE_BOOT_COMPLETED<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--normal\">Normal<\/span><\/td>\n<td>Restoring scheduled notifications after reboot<\/td>\n<\/tr>\n<tr>\n<td><code>SCHEDULE_EXACT_ALARM<\/code><\/td>\n<td><span class=\"stf-pill stf-pill--normal\">Normal<\/span><\/td>\n<td>Precise timing of local notifications<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"network\">3. Network &amp; connectivity<\/h2>\n<h3>3.1&nbsp;&nbsp;<code>INTERNET<\/code><\/h3>\n<p><strong>Why.<\/strong> Every meaningful action &mdash; signing in, reading your application list, uploading a document, receiving a clarification from your advisor &mdash; requires a network call to Supabase or to Google&rsquo;s Firebase Cloud Messaging servers.<\/p>\n<p><strong>How we scope it.<\/strong> Traffic is forced over TLS 1.3. Cleartext HTTP is disabled at OS level through <code>network_security_config.xml<\/code> and <code>android:usesCleartextTraffic=&quot;false&quot;<\/code>.<\/p>\n<h3>3.2&nbsp;&nbsp;<code>ACCESS_NETWORK_STATE<\/code><\/h3>\n<p><strong>Why.<\/strong> The <code>connectivity_plus<\/code> plugin uses this to tell the app whether you are on Wi-Fi, mobile data or offline, so we can queue uploads, show an offline banner and retry automatically.<\/p>\n<p><strong>What we do not do.<\/strong> This permission does not give the app visibility into SSID, MAC address or IP address of your network.<\/p>\n<h2 id=\"camera\">4. Camera &mdash; <code>CAMERA<\/code><\/h2>\n<p><strong>Why.<\/strong> Two places in the app capture a camera image: the Documents upload flow (photographing a KYC document) and the Profile Photo flow. Both are triggered only by an explicit &ldquo;Use camera&rdquo; tap; no background capture occurs.<\/p>\n<p><strong>How.<\/strong> The system camera intent is launched via the <code>image_picker<\/code> Flutter plugin &mdash; STF Capital does not read the raw camera sensor stream.<\/p>\n<p><strong>If you decline.<\/strong> The &ldquo;Use camera&rdquo; option is hidden; library uploads continue to work.<\/p>\n<h2 id=\"storage\">5. Media &amp; files<\/h2>\n<h3>5.1&nbsp;&nbsp;<code>READ_MEDIA_IMAGES<\/code> and <code>READ_MEDIA_VIDEO<\/code> (Android 13+)<\/h3>\n<p>Modern per-type permissions for the photo picker. Only requested for the upload feature; audio and arbitrary MIME types are not requested.<\/p>\n<h3>5.2&nbsp;&nbsp;<code>READ_EXTERNAL_STORAGE<\/code> and <code>WRITE_EXTERNAL_STORAGE<\/code> (Android 12 and below)<\/h3>\n<p>Both carry <code>android:maxSdkVersion=&quot;32&quot;<\/code>, so Android does not grant them on API 33+. Legacy permissions active only on devices that need them.<\/p>\n<h3>5.3&nbsp;&nbsp;File validation and size limits<\/h3>\n<ul>\n<li>Max size <strong>15 MB<\/strong> per file.<\/li>\n<li>Accepted types: PDF, PNG, JPG, JPEG, WEBP, DOC, DOCX, XLS, XLSX.<\/li>\n<li>Files are inspected by magic-byte verification before upload.<\/li>\n<\/ul>\n<h2 id=\"biometric\">6. Biometric authentication<\/h2>\n<p><strong>Permissions:<\/strong> <code>USE_BIOMETRIC<\/code> on Android&nbsp;9+ and <code>USE_FINGERPRINT<\/code> for the legacy API on older devices.<\/p>\n<ul>\n<li>Biometrics are strictly opt-in via the Biometric Setup screen.<\/li>\n<li>The biometric template never leaves your device. The comparison happens inside the device&rsquo;s secure element and returns only a pass\/fail signal.<\/li>\n<li>Falls back to PIN or password if the sensor is disabled.<\/li>\n<\/ul>\n<h2 id=\"notifications\">7. Notifications &mdash; <code>POST_NOTIFICATIONS<\/code><\/h2>\n<p>Notifications cover: application-status changes, advisor clarifications or deal documents, and admin work-queue reminders. Routed through FCM to a single device token per signed-in device.<\/p>\n<p>Notification previews never expose sensitive amounts or products on the lock screen.<\/p>\n<p><strong>If you decline.<\/strong> Status updates still reach the app in real-time through a websocket subscription; you simply won&rsquo;t receive OS-level alerts.<\/p>\n<h2 id=\"boot\">8. Boot &amp; scheduling<\/h2>\n<h3>8.1&nbsp;&nbsp;<code>RECEIVE_BOOT_COMPLETED<\/code><\/h3>\n<p>Re-registers scheduled local notifications after device reboot. Does <em>not<\/em> auto-launch the application.<\/p>\n<h3>8.2&nbsp;&nbsp;<code>SCHEDULE_EXACT_ALARM<\/code><\/h3>\n<p>Allows the notifications plugin to schedule reminders at an exact wall-clock moment. Used sparingly, never for marketing.<\/p>\n<h2 id=\"vibrate\">9. Vibration &mdash; <code>VIBRATE<\/code><\/h2>\n<p>If you select &ldquo;Vibrate&rdquo; notification mode on the Profile screen, a short vibration pattern accompanies alerts. Silent or Sound modes never vibrate.<\/p>\n<h2 id=\"not-requested\">10. What we deliberately do <em>not<\/em> request<\/h2>\n<ul>\n<li><strong>Location<\/strong> &mdash; neither coarse nor fine nor background.<\/li>\n<li><strong>Contacts, calendar, SMS, phone state, microphone, body sensors.<\/strong><\/li>\n<li><strong>Bluetooth scanning, accessibility services, device administrator.<\/strong><\/li>\n<li><strong>Install other packages or query installed applications.<\/strong><\/li>\n<\/ul>\n<h2 id=\"runtime-ux\">11. Runtime prompt experience<\/h2>\n<ol>\n<li><strong>Pre-prompt.<\/strong> A short in-app sheet explains what the permission enables. Buttons: &ldquo;Continue&rdquo; or &ldquo;Not now&rdquo;.<\/li>\n<li><strong>System prompt.<\/strong> If you tap &ldquo;Continue&rdquo;, Android takes over with its own dialog &mdash; the only prompt that can actually grant the permission.<\/li>\n<\/ol>\n<p>If you decline, we don&rsquo;t nag. Next time you invoke a feature that needs it, we show a calm hint explaining how to enable it in Settings.<\/p>\n<h2 id=\"revoke\">12. Revoking a permission you previously granted<\/h2>\n<ol>\n<li>Open the Android <strong>Settings<\/strong> app.<\/li>\n<li>Tap <strong>Apps<\/strong> \u2192 <strong>STF Capital<\/strong>.<\/li>\n<li>Tap <strong>Permissions<\/strong> and toggle off.<\/li>\n<\/ol>\n<p>Android&nbsp;12+ also auto-revokes permissions for apps you haven&rsquo;t used in a while &mdash; we transparently re-request with the same explanatory pre-prompt on next use.<\/p>\n<h2 id=\"android-versions\">13. How the permissions differ by Android version<\/h2>\n<table class=\"stf-table\">\n<thead>\n<tr>\n<th>Android version<\/th>\n<th>Runtime prompts<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Android 7.0 &ndash; 12<\/td>\n<td><code>CAMERA<\/code>, <code>READ\/WRITE_EXTERNAL_STORAGE<\/code>, <code>USE_BIOMETRIC<\/code><\/td>\n<\/tr>\n<tr>\n<td>Android 13 (API 33)<\/td>\n<td><code>CAMERA<\/code>, <code>READ_MEDIA_IMAGES<\/code>, <code>READ_MEDIA_VIDEO<\/code>, <code>POST_NOTIFICATIONS<\/code>, <code>USE_BIOMETRIC<\/code><\/td>\n<\/tr>\n<tr>\n<td>Android 14+ (API 34+)<\/td>\n<td>Same as Android 13; <code>SCHEDULE_EXACT_ALARM<\/code> restricted per Google policy<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"play-review\">14. Google Play Permissions Review alignment<\/h2>\n<table class=\"stf-table\">\n<thead>\n<tr>\n<th>Google Play policy<\/th>\n<th>Our justification<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Camera must be user-initiated<\/td>\n<td>Only on explicit &ldquo;Use camera&rdquo; tap. No background capture.<\/td>\n<\/tr>\n<tr>\n<td>Media permissions narrowly scoped<\/td>\n<td><code>READ_MEDIA_IMAGES<\/code> and <code>READ_MEDIA_VIDEO<\/code> only, not audio.<\/td>\n<\/tr>\n<tr>\n<td>Biometric must be opt-in<\/td>\n<td>Strictly opt-in via Biometric Setup screen.<\/td>\n<\/tr>\n<tr>\n<td>Notifications must have rationale<\/td>\n<td>Pre-prompt shows rationale before the system dialog.<\/td>\n<\/tr>\n<tr>\n<td>No tracking \/ advertising<\/td>\n<td>Confirmed in the Privacy Policy.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"decline\">15. What happens if you decline<\/h2>\n<table class=\"stf-table\">\n<thead>\n<tr>\n<th>Declined permission<\/th>\n<th>Effect<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>CAMERA<\/code><\/td>\n<td>&ldquo;Use camera&rdquo; hidden; library uploads still work.<\/td>\n<\/tr>\n<tr>\n<td><code>READ_MEDIA_*<\/code><\/td>\n<td>Library picker empty; camera uploads still work.<\/td>\n<\/tr>\n<tr>\n<td><code>POST_NOTIFICATIONS<\/code><\/td>\n<td>No OS alerts; state visible when you open the app.<\/td>\n<\/tr>\n<tr>\n<td><code>USE_BIOMETRIC<\/code><\/td>\n<td>Biometric unlock not offered; PIN\/password continues.<\/td>\n<\/tr>\n<tr>\n<td><code>ACCESS_NETWORK_STATE<\/code><\/td>\n<td>No offline banner; retries happen on a fixed interval.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"ios\">16. A note on iOS<\/h2>\n<p>The iOS build follows the same principles but through Apple&rsquo;s <code>NSUsageDescription<\/code> keys &mdash; <code>NSCameraUsageDescription<\/code>, <code>NSPhotoLibraryUsageDescription<\/code>, <code>NSFaceIDUsageDescription<\/code> and the system notification authorisation prompt. Same &ldquo;necessity, least privilege, graceful degradation&rdquo; principles apply.<\/p>\n<h2 id=\"contact\">17. Questions about a specific permission<\/h2>\n<p>Write to <a href=\"mailto:inquiries@stfcapital.org\">inquiries@stfcapital.org<\/a> with the subject &ldquo;Permissions Query&rdquo;. We welcome scrutiny &mdash; it makes the app better.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Document 02 of 04 \u00b7 Permissions Every permission the STF&nbsp;Capital app asks for, and why. Android gives applications a powerful but explicit permission model: if the app wants to use your camera, read files from shared storage, deliver notifications or wake up after your phone reboots, it must declare that intention in its manifest and &hellip; <\/p>\n<p class=\"more-link-wrap\"><a href=\"https:\/\/stfcapital.org\/index.php\/legal\/app-permissions\/\" class=\"more-link\"><span>Read More<span class=\"screen-reader-text\"> &#8220;App Permissions&#8221;<\/span><\/span><i class=\"opal-icon-arrow-right\" aria-hidden=\"true\"><\/i><\/a><\/p>\n","protected":false},"author":6309,"featured_media":0,"parent":6092,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"class_list":["post-6096","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/pages\/6096","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/users\/6309"}],"replies":[{"embeddable":true,"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/comments?post=6096"}],"version-history":[{"count":1,"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/pages\/6096\/revisions"}],"predecessor-version":[{"id":6097,"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/pages\/6096\/revisions\/6097"}],"up":[{"embeddable":true,"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/pages\/6092"}],"wp:attachment":[{"href":"https:\/\/stfcapital.org\/index.php\/wp-json\/wp\/v2\/media?parent=6096"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}