Preparing for scoped storage (Android Dev Summit '19)

Preparing for scoped storage (Android Dev Summit '19) — Android Developers

Android Developers

AI-assisted summary of Preparing for scoped storage (Android Dev Summit '19) — original source. Check the original for full context.

Source published:

Key ideas

  • Android 10 introduced Scoped Storage to isolate app data and clean up external storage, with 98% of apps targeting Android 10 adopting it without declaring the temporary legacy opt-out flag. (5:23)
  • Apps can contribute to shared media collections (Images, Video, Audio) and the Downloads folder without any runtime permissions, but reading third-party files outside media collections requires the Storage Access Framework (SAF). (2:05)
  • In response to developer feedback, the next Android release will reintroduce direct POSIX file path access for reading media by routing calls through MediaStore under the hood, alongside batch dialogs for modifying third-party files. (14:37)
  • Apps requiring broad filesystem access, such as file managers and backup utilities, will require a dedicated Special App Access permission subject to a Google Play declaration and review process. (19:52)

Detailed notes

## Background Published on YouTube by the Android Developers channel on October 24, 2019, this Android Dev Summit '19 session is presented by Android Framework team members Roxanna Aliabadi, Zimuzo Ezeozue, and Yacine Rezgui. The presentation provides a roadmap and practical guide for developers adapting to the scoped storage architecture introduced in Android 10.

## TL;DR The speakers detail the shift to Scoped Storage in Android 10, explaining how the platform restricts broad disk access to protect user privacy, prevent orphaned files, and sandbox application data. In response to community feedback on early disruption, the team outlines key adjustments planned for the subsequent Android release, such as bridging POSIX file paths to MediaStore, enabling batch edit consent dialogs, and establishing a Google Play-governed access path for dedicated file managers. Practical code walkthroughs demonstrate how to query media via ContentResolver, handle permission challenges through RecoverableSecurityException, and integrate the Storage Access Framework for document picking without requesting broad storage permissions.

## Atmosphere & style The talk maintains a pragmatic, responsive, and reassuring tone as the speakers directly acknowledge the disruption caused by early Scoped Storage rollouts and emphasize how developer feedback shaped subsequent platform changes. Roxanna Aliabadi and Zimuzo Ezeozue provide structured, high-level architectural clarity before Yacine Rezgui leads an earnest, code-focused demonstration with relatable live-stage moments. The session feels like an open engineering dialogue, balancing firm platform privacy mandates with an accommodating attitude toward practical developer workflows.

## Bulletin - [05:23](https://www.youtube.com/watch?v=UnJ3amzJM94&t=323s) Android 10 introduced Scoped Storage to isolate app data and clean up external storage, with 98% of apps targeting Android 10 adopting it without declaring the temporary legacy opt-out flag. - [02:05](https://www.youtube.com/watch?v=UnJ3amzJM94&t=125s) Apps can contribute to shared media collections (Images, Video, Audio) and the Downloads folder without any runtime permissions, but reading third-party files outside media collections requires the Storage Access Framework (SAF). - [14:37](https://www.youtube.com/watch?v=UnJ3amzJM94&t=877s) In response to developer feedback, the next Android release will reintroduce direct POSIX file path access for reading media by routing calls through MediaStore under the hood, alongside batch dialogs for modifying third-party files. - [19:52](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1192s) Apps requiring broad filesystem access, such as file managers and backup utilities, will require a dedicated Special App Access permission subject to a Google Play declaration and review process.

## Key takeaways - [00:00](https://www.youtube.com/watch?v=UnJ3amzJM94&t=0s) Historically, roughly half of all Android apps requested broad storage permissions, leading to scattered, orphaned files on external storage when apps were uninstalled. - [02:05](https://www.youtube.com/watch?v=UnJ3amzJM94&t=125s) Scoped Storage is anchored on three core principles: better file attribution, protecting private app data, and safeguarding user data such as private photos and tax forms. - [02:05](https://www.youtube.com/watch?v=UnJ3amzJM94&t=125s) Apps have unrestricted, permissionless access to their own app-specific directories on both internal storage and SD cards under Android 10. - [13:11](https://www.youtube.com/watch?v=UnJ3amzJM94&t=791s) Accessing EXIF geographic location coordinates requires the ACCESS_MEDIA_LOCATION runtime permission, preventing unauthorized tracking via shared photos. - [13:11](https://www.youtube.com/watch?v=UnJ3amzJM94&t=791s) Developers can invoke MediaStore.setRequireOriginal() to ensure bit-for-bit fidelity and avoid silent stripping of sensitive image metadata. - [05:23](https://www.youtube.com/watch?v=UnJ3amzJM94&t=323s) The requestLegacyExternalStorage manifest flag was introduced as a temporary bridge for Android 10, but Google announced it will be fully deprecated in future releases. - [05:23](https://www.youtube.com/watch?v=UnJ3amzJM94&t=323s) Scoped Storage enforcement in the subsequent release will be tied strictly to targetSdkVersion rather than being forced universally across all installed legacy apps. - [10:06](https://www.youtube.com/watch?v=UnJ3amzJM94&t=606s) The legacy WRITE_EXTERNAL_STORAGE permission is slated for deprecation and will effectively function as a synonym for read access to media files. - [14:37](https://www.youtube.com/watch?v=UnJ3amzJM94&t=877s) Direct POSIX file path I/O acts as an internal delegation wrapper over MediaStore, introducing minor overhead on file open calls while preserving all MediaStore security rules. - [28:33](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1713s) Modifying or deleting media owned by another app triggers a RecoverableSecurityException, which provides a PendingIntent to display a user consent prompt. - [18:11](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1091s) The upcoming platform release will introduce bulk consent dialogs, eliminating the need to pop individual confirmation dialogs for each file edit. - [19:52](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1192s) The Storage Access Framework's ACTION_OPEN_DOCUMENT_TREE intent will explicitly block user selection of root storage directories, the Downloads directory, and Android/data. - [30:15](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1815s) Document-based workflows like email attachments should rely on SAF intents (such as ACTION_OPEN_DOCUMENT and ACTION_CREATE_DOCUMENT) instead of asking for runtime storage permissions. - [30:15](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1815s) Permissions obtained via the system file picker are temporary across device reboots unless explicitly retained using takePersistableUriPermission(). - [33:12](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1992s) Hardcoded file paths must be avoided in favor of building Content URIs dynamically using platform constants and MediaStore IDs.

## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=UnJ3amzJM94&t=0s) Introduction to Scoped Storage and the Problem with Shared Storage

Roxanna Aliabadi, a product manager on the Android Framework team, introduces the session alongside colleagues Zimuzo Ezeozue and Yacine Rezgui. In Android 10, the team unveiled a fundamental architectural shift known as Scoped Storage to reform how apps interact with on-device files. To establish context, Roxanna distinguishes between private and shared storage. Private storage consists of dedicated app directories located at `Android/data/<package_name>` on internal storage, which remain completely hidden from any other application, regardless of whether that other app holds storage permissions. Everything outside these boundaries—including media collections and external directories residing on SD cards—constitutes shared storage.

Historically, roughly half of all Android apps requested the broad storage permission. However, the vast majority of these applications never actually required such sweeping authority. Roxanna observes that most were merely executing simple tasks such as picking a profile photo in a social app or downloading an email attachment. Giving applications unconstrained write access created a severe file-hygiene crisis across the ecosystem: apps frequently scattered miscellaneous files across external storage and left them stranded upon uninstallation. These orphaned files accumulated over time, consuming crucial space on devices where end users were already struggling with low disk capacity.

```mermaid flowchart TD accTitle: Android Storage Architecture Comparison accDescr: Contrasts private app storage with shared storage, illustrating access controls and legacy sprawl issues.

subgraph Private["Private Internal Storage"] P1["android/data/package_name"] P2["Only accessible to owning app"] P1 --- P2 end

subgraph Shared["Shared External Storage"] S1["Organized Media (Images, Video, Audio)"] S2["Downloads Collection"] S3["SD Card App Directories"] S4["Unorganized Disk Space (Scattered files)"] end

Private -.->|"Isolated from other apps"| Shared ```

[02:05](https://www.youtube.com/watch?v=UnJ3amzJM94&t=125s) Design Principles and Android 10 Implementations

To eliminate indiscriminate disk access while still satisfying real application requirements, the Android team designed Scoped Storage around three core principles: better attribution, protecting app data, and protecting user data. Better attribution ensures the operating system explicitly tracks which application created each file, simplifying user storage management and ensuring that when an application is uninstalled, its lingering data is automatically purged unless the user chooses to retain it. Protecting app data involves closing access loopholes so external app directories on SD cards cannot be casually snooped on by other software. Protecting user data ensures sensitive files—such as personal photos downloaded from private chats or tax returns saved as PDFs—are completely shielded from third-party apps holding standard storage permissions.

Under Android 10 Scoped Storage, applications receive unrestricted, permissionless access to their own internal and external package directories, meaning writing to an app-specific SD card folder no longer requires any manifest storage permission. Additionally, apps can contribute new files directly into organized shared collections (Images, Video, Audio, and the new Downloads collection) without requesting any user permission. The traditional runtime storage permission has been redefined: granting it no longer gives a blanket view of the file system, but instead provides read access strictly to media collections. Furthermore, because EXIF metadata can reveal sensitive personal locations, Android 10 introduces the `ACCESS_MEDIA_LOCATION` permission; if an application fails to declare and obtain this permission, geographic coordinates are automatically stripped whenever it reads media files.

- Reading general documents (such as PDF files) requires delegating access through the system picker via the Storage Access Framework (SAF). - Writing files outside of dedicated app sandboxes or organized media collections requires user selection via the system file picker. - System picker requirements ensure the user retains complete agency over where unorganized files are placed on disk.

[05:23](https://www.youtube.com/watch?v=UnJ3amzJM94&t=323s) Ecosystem Feedback, Legacy Flags, and the Next Android Release

When Scoped Storage was introduced during the early beta phase of Android 10, the team initially enforced it across all applications regardless of their `targetSdkVersion`. The developer community pushed back vigorously, emphasizing that such an enormous architectural disruption was impossible to adopt within the beta timeline. In response, Google added the `requestLegacyExternalStorage` manifest attribute, allowing apps targeting Android 10 to temporarily opt out and preserve legacy storage behavior. Roxanna notes that among apps targeting Android 10, 98% did not declare this legacy flag, validating that the scoped model meets the needs of mainstream apps.

> “This shows us that the changes we introduced with Scoped Storage are acceptable to most developers.” — Roxanna Aliabadi

Nevertheless, the framework team recognized that many applications had not yet migrated to Android 10, and the remaining 2% represented critical use cases facing real friction. Developers highlighted several recurring pain points: 1. **File paths and native code:** Android 10 broke support for standard POSIX file paths and C/C++ native libraries when interacting with media files. 2. **Heavy-duty storage apps:** Utilities like file managers and backup/restore suites struggled with SAF, reporting severe performance bottlenecks when traversing deeply nested folder trees, alongside awkward user onboarding flows that required users to select disk roots manually. 3. **Muddled permission semantics:** The storage permission meant media-only access for updated apps, but wide-open disk access for un-migrated apps, confusing users and developers alike.

To avoid developers writing code for Android 10 that they would have to undo immediately afterward, Roxanna outlines upcoming storage changes planned for the subsequent Android release. The system permission dialog will visually distinguish whether an app is receiving media-only access or broad storage access. Native code and file paths are returning for reading media files, and APIs for editing or deleting files created by other apps will be streamlined with bulk operations. For specialized utilities like file managers, Android is introducing a dedicated "Special App Access" broad-storage permission subject to Google Play approval. Furthermore, SAF will block users from granting access to raw external app directories, closing an ongoing privacy leak. Critically, the team decided to enforce Scoped Storage based on `targetSdkVersion` rather than applying it universally across all installed apps:

> “Last year, we did say that we would be enforcing this regardless of target SDK for all apps on the next release of Android. But really, we think that the best thing for the users is to introduce these changes gradually.” — Roxanna Aliabadi

[10:06](https://www.youtube.com/watch?v=UnJ3amzJM94&t=606s) Media Collections and Permissions Deep Dive

Zimuzo Ezeozue takes over to detail the technical mechanics of media collections across Android 10 and the subsequent platform release. Since Android's earliest days, shared media has been organized into Audio, Images, and Video tables. Under Android 10, any application can insert new files into these collections without requesting runtime storage permissions. An application also retains implicit, unrestricted edit and deletion rights over any media files it contributed itself.

Reading media files authored by other applications still requires the `READ_EXTERNAL_STORAGE` permission. Looking ahead to the next Android release, the legacy `WRITE_EXTERNAL_STORAGE` permission will be deprecated, acting merely as a synonym for read access to media files. Modifying or deleting media that belongs to other applications is strictly prohibited unless explicit user consent is granted through a system confirmation dialog. As Zimuzo emphasizes, this prevents rogue or buggy applications from altering or deleting precious user pictures without their clear knowledge and approval.

[11:30](https://www.youtube.com/watch?v=UnJ3amzJM94&t=690s) Permission Strings and the Downloads Collection

Depending on the target SDK version of an application, users will encounter two different permission strings when storage access is requested. If an app targets the upcoming Android release, the system presents a modernized permission string that explicitly asks only for access to media files on external storage. Conversely, applications targeting older releases will continue to display the legacy storage permission prompt that requests broad access to the entire external storage. This distinction is designed so that “users will understand how much access your app is requesting.”

Android 10 also introduced a dedicated Downloads collection designed specifically for sharing non-media files across applications. Contributing files to this collection, as well as updating or deleting files that your own app contributed, requires no permissions whatsoever. Accessing non-media files contributed by third-party applications, however, differs fundamentally from media handling: the standard `READ_EXTERNAL_STORAGE` permission grants zero access to non-media files created by other apps. To access those files, an app must trigger the system picker via the Storage Access Framework (SAF) APIs. Once a user explicitly chooses a file or folder through SAF, the app receives full read, edit, and delete permissions for that selection without requiring subsequent consent prompts. This strict boundary protects sensitive user documents, such as bank statements, from unwarranted inspection.

```mermaid flowchart TD accTitle: Accessing Non-Media Files Flowchart accDescr: Decision flow showing how an app accesses non-media files depending on whether it owns the file.

Start["Access Non-Media File"] --> Owner{"App contributed file?"} Owner -- "Yes" --> Direct["Full Read / Edit / Delete\n(No permissions required)"] Owner -- "No" --> SAF["Storage Access Framework\n(Launch system file picker)"] SAF --> UserGrant["User explicitly selects file"] UserGrant --> FullAccess["Full Read / Edit / Delete Granted\n(No further consent needed)"] ```

[13:11](https://www.youtube.com/watch?v=UnJ3amzJM94&t=791s) Sensitive Metadata Redaction and MediaStore.setRequireOriginal

Protecting sensitive user data stands as a core priority on Android. Starting in Android 10, the platform transparently strips sensitive metadata—most notably geographic location coordinates—whenever an app inspects media files that were contributed by other applications. If an application legitimately requires location tags or similar EXIF information, it must declare and request the `ACCESS_MEDIA_LOCATION` runtime permission alongside `READ_EXTERNAL_STORAGE`.

Even though `ACCESS_MEDIA_LOCATION` is a runtime permission, it does not show up as a toggle in the system Settings UI. Furthermore, holding `READ_EXTERNAL_STORAGE` does not guarantee that location access will be granted. Zimuzo Ezeozue warns that this caveat is “especially true on enterprise devices where a device policy client can modify or change permissions requested by other apps.” For applications where bit-for-bit fidelity is critical, developers can invoke `MediaStore.setRequireOriginal()`. This API ensures that the app either receives the exact original byte stream from the storage media or throws an exception if redaction would have taken place, preventing subtle corruption or silent data loss in workflows that rely on unaltered image buffers.

- `ACCESS_MEDIA_LOCATION` must be defined in the app manifest and requested at runtime. - The permission has no user-facing toggle inside the standard system Settings app. - `MediaStore.setRequireOriginal()` guarantees either unredacted original bytes or an explicit exception.

[14:37](https://www.youtube.com/watch?v=UnJ3amzJM94&t=877s) File Path Access and Performance Tradeoffs

Android 10 initially locked down direct file path access across common shared directories to satisfy privacy benchmarks. However, the engineering team realized that migrating legacy codebases all at once proved painful. Zimuzo Ezeozue explains: “However, after going through the developer feedback, we saw that this required a lot of effort from you to adopt straight away. And in the next Android release, we will likely do this work for you.” Although MediaStore remains the strongly recommended path forward, Google recognizes that many apps rely on third-party C and C++ native libraries that operate strictly on POSIX file paths.

```mermaid flowchart LR accTitle: File Path Delegation to MediaStore accDescr: Architecture showing how POSIX file path calls delegate to MediaStore under the hood.

subgraph NativeApp["Application Layer"] FP["File Path / POSIX I/O\n(C / C++ / java.io.File)"] MS["MediaStore API Direct"] end

subgraph PlatformLayer["Android Platform Layer"] Bridge["Internal Delegation Layer\n(Path mapping & security checks)"] MediaStoreEngine["MediaStore Engine"] end

FP --> Bridge Bridge --> MediaStoreEngine MS --> MediaStoreEngine ```

Under the hood, all file path I/O calls are transparently delegated to MediaStore, acting essentially as a convenience wrapper. Consequently, using direct file paths confers no feature advantage and introduces a minor performance penalty. All standard MediaStore rules apply to file path operations: - Media items must reside in their designated directory types (e.g., audio files cannot be placed in the `Pictures/` folder). - Reading third-party media through file paths still mandates `READ_EXTERNAL_STORAGE`. - Location redaction still occurs unless `ACCESS_MEDIA_LOCATION` is active. - Non-media files (such as PDFs) must be written exclusively to `Download/`. - Accessing non-media files generated by other apps through file paths still requires initial authorization via SAF. - Files created via file paths are properly attributed to the calling app and count against its storage quota.

While internal benchmarks covering sequential and random I/O demonstrate that the overhead of file path delegation is negligible at low I/O rates, opening files and reading the initial bytes remains computationally expensive. Zimuzo Ezeozue cautions developers against thrashing file descriptors: “So if you're going to use file paths, please try to avoid opening and closing the same file multiple times.” Apps performing high-throughput I/O—in the neighborhood of hundreds of megabytes per second—are invited to consult directly with the storage team at the conference sandbox.

[18:11](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1091s) User Consent for Media Modifications and Batching Improvements

Under Android 10, modifying or deleting media files created by other apps mandates explicit user consent obtained through a system dialog triggered by MediaStore. Once the user approves, the platform issues a callback, after which the application can edit or delete the file using either MediaStore APIs or standard file paths. Attempting to bypass this dialog by modifying third-party media directly through file paths will fail immediately without prompting the user.

To streamline the user experience, the next Android version addresses a major community request by introducing batch modification requests:

> “So now you can batch multiple edit requests in one dialog instead of popping one dialog per request, as it was in the case of Android 10.” — Zimuzo Ezeozue

While developers retain the option to copy a shared file into their app-specific external directory to perform one-off edits, this pattern is discouraged for general use because it bloats disk usage and clutters the user's storage.

[19:52](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1192s) SAF Restrictions, Special App Access, and the Legacy Flag Deprecation

Roxanna Aliabadi returns to outline further refinements to shared storage access. Because some applications abused `ACTION_OPEN_DOCUMENT_TREE` to gain sweeping access over external storage, the platform is tightening the user experience for directory pickers. In the upcoming release of Android, `ACTION_OPEN_DOCUMENT_TREE` will prevent users from selecting the storage root, the entire `Download/` directory, or any directory located under `Android/data/`. Applications can still use document pickers to access individual files located within the Downloads directory, but they can no longer acquire blanket authorization for the whole directory tree.

```mermaid flowchart TD accTitle: SAF Tree Restrictions and Special App Access accDescr: Structural rules for directory selections under ACTION_OPEN_DOCUMENT_TREE and exceptions for whitelisted tools.

subgraph SAFTreeRestrictions["ACTION_OPEN_DOCUMENT_TREE Blocklist"] R1["Storage Root (/) - BLOCKED"] R2["Android/data/ - BLOCKED"] R3["Downloads/ Folder - BLOCKED"] AllowedDoc["Individual file selection via SAF - ALLOWED"] end

subgraph SpecialAccessPath["Special App Access (Broad Storage)"] Form["Play Console Declaration Form"] --> Review{"Google Play Whitelist"} Review -- "Approved" --> UserGrantPrompt["User Grants Broad Access"] UserGrantPrompt --> UnfilteredMS["Unfiltered MediaStore\n(Includes Non-Media Files)"] UserGrantPrompt --> DeniedAppDirs["External App Dirs (Android/data/)\nSTILL BLOCKED"] end ```

For applications whose core functionality fundamentally depends on broad filesystem access—such as dedicated file managers or backup and restore solutions—Google is introducing a special app access permission. To obtain this capability, developers must submit a formal declaration form via the Google Play Developer Console:

> “Only apps that can prove this need will be granted this access.” — Roxanna Aliabadi

Whitelisted applications that receive the user's approval get an unfiltered view of MediaStore, including non-media files. However, this grant does not extend to the private external app directories of other apps (`Android/data/`), which remain protected. Roxanna Aliabadi clarifies that “this access will not be granted for apps that simply want to create their own file picking experience. Those apps should use the system picker.”

Finally, Aliabadi addresses the migration timeline. The `requestLegacyExternalStorage` manifest attribute introduced in Android 10 as a transitional escape hatch will be completely retired in future versions. Developers are advised to test Scoped Storage behaviors immediately and migrate any orphaned documents or media files residing outside the standard organized directories into app-specific storage before targeting Android 10, or they will lose access to those files entirely.

[23:35](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1415s) Scoped Storage Summary and Upcoming Changes

Roxanna Aliabadi recaps the state of Scoped Storage introduced in Android 10 along with features arriving in the next Android version. Under the current Android 10 model, media files can be contributed to shared storage without requesting any permissions, and non-media files can be contributed straight to the `Downloads` directory. However, reading non-media files is guarded: apps cannot simply scan them directly and must instead route file-reading through the system picker using Storage Access Framework (SAF) APIs. Furthermore, accessing sensitive location metadata embedded in images and videos requires apps to explicitly request the `ACCESS_MEDIA_LOCATION` permission.

Looking ahead to the subsequent release of Android, Aliabadi announces that file path access will be reintroduced specifically for reading media. The platform will also revamp the Media Modification APIs by adding support for bulk operations. Concurrently, the team plans to restrict the Storage Access Framework so users can no longer grant access to broad shared storage roots or sensitive directories. For specialized applications such as file managers, a dedicated app access mechanism will be established, gated by Google Play whitelisting. As Roxanna Aliabadi emphasizes when describing the roadmap, “And all this will be enforced by target SDK.” She then hands the presentation over to Yacine Rezgui to walk through concrete development use cases.

- Media can be contributed without storage permissions. - Non-media contributions go to the `Downloads` collection; reading non-media files mandates the Storage Access Framework. - Reading EXIF geolocation metadata requires the runtime permission `ACCESS_MEDIA_LOCATION`. - The upcoming Android release will reintroduce direct file path read access for media and bulk modification prompts. - Storage Access Framework will restrict user selection of broad root directories and sensitive folders. - Play Store whitelisting will govern special broad-access permissions for approved categories.

---

[24:59](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1499s) Querying Media with the MediaStore API

Yacine Rezgui takes over to demonstrate practical code patterns, acknowledging that picking the correct storage API can be daunting: “So as Roxy and Zim mentioned, we're simplifying the developer experience on Scoped Storage. But with all these APIs, it may not be easy to figure out which one you should use in your application.” To clarify, Rezgui introduces the first scenario: a media player application that needs to discover, display, and play all video files located on the user's device. For this requirement, developers should rely on the `MediaStore` API. `MediaStore` maintains an indexed catalog of media files, which provides strong performance benefits for discoverability compared to manually traversing directory trees.

Because this media player accesses files created by other apps on the device, it must declare the `READ_EXTERNAL_STORAGE` permission in `AndroidManifest.xml`. Querying `MediaStore` is done via `ContentResolver`, which exposes an interface structured much like a traditional SQL query. The caller defines a projection to specify the desired columns, supplies selection arguments to filter the rows, and sets an ordering clause.

```mermaid flowchart TD accTitle: MediaStore Query Flow accDescr: Flow diagram showing how a media app queries the MediaStore via ContentResolver to retrieve video items.

subgraph Preparation ["1. Query Configuration"] A["Set Projection<br>(ID, Display Name, Duration, Size)"] B["Define Filter Clause<br>(Duration &ge; 5 minutes)"] C["Specify Sort Order<br>(By Duration)"] end

subgraph Execution ["2. Resolution"] D["ContentResolver.query(...)<br>against Video Content URI"] E["Return Cursor"] end

subgraph Processing ["3. Result Processing"] F["Cache Column Indices"] G["Iterate Cursor Rows"] H["Append ID to Base URI<br>Build Item Content URI"] end

Preparation --> D D --> E E --> F F --> G G --> H ```

In the media player implementation, the projection selects the unique ID column (`_ID`), display name, duration, and file size from the `MediaStore.Video.Media` column contract. Rezgui shows how to filter for videos lasting five minutes or longer, noting that because duration is stored in milliseconds, the query argument must convert minutes to milliseconds accordingly. The query executes against the external `MediaStore` video content URI and sorts the results by duration.

When consuming the returned `Cursor`, Rezgui catches a brief slip (“We need to-- sorry. My bad.”) before explaining best practices for performance: index lookups must be cached outside the row iteration loop so the app avoids repeated index fetches and prevents runtime exceptions if a column is missing. As the app loops through each cursor row, it takes the base external content URI for videos and appends the specific media ID to construct the exact content URI for playback and UI binding.

---

[28:33](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1713s) Editing Media and Handling User Consent

Rezgui moves to the second scenario: a photo editing application. This type of application not only creates brand-new images but also edits or deletes images captured or saved by other apps. Because the application manipulates media outside its own attribution footprint, it still requires the `READ_EXTERNAL_STORAGE` runtime permission. When modifying or deleting an image owned by another application, the operating system intervenes to ensure security by prompting the user for approval. Rezgui highlights an upcoming platform enhancement: “From the next Android release, you will be able to bulk all of those requests within a single dialog.”

If the photo app provides features that depend on where an image was taken, the developer must explicitly request the `ACCESS_MEDIA_LOCATION` permission to read EXIF GPS metadata. Rezgui warns developers never to treat this permission as guaranteed: “Remember that you have to double check if you still have access to this media location. You should not assume having it all the time.”

```mermaid flowchart LR accTitle: Media Modification Exception Flow accDescr: Flowchart illustrating the RecoverableSecurityException handling loop when modifying another app's media file.

A["Open FileDescriptor<br>(Write Mode)"] --> B{"Owned by<br>another app?"} B -- "No" --> C["Perform Edit / Delete"] B -- "Yes" --> D["RecoverableSecurityException"] D --> E["Extract PendingIntent"] E --> F["Launch System Consent Dialog"] F --> G{"User Consents?"} G -- "Yes" --> H["Re-open FileDescriptor<br>Complete Operation"] G -- "No" --> I["Abort Operation"] ```

The underlying code flow for editing third-party media involves attempting to open the target file's file descriptor in write mode (`"w"`). If the app lacks write privileges for that specific file, the system throws a `RecoverableSecurityException`. Within this exception object, the platform provides a `PendingIntent`. The application triggers this intent to display the system confirmation dialog to the user. Once the user approves the prompt, the application re-opens the file descriptor, which now grants read/write access to complete the modification.

---

[30:15](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1815s) Productivity Apps and Storage Access Framework (SAF)

The third use case centers on productivity software, such as an email client that needs to attach arbitrary documents—PDFs, ZIP archives, or text files—to an outgoing message. In this situation, apps should use the Storage Access Framework (SAF). A major advantage of SAF is that the app does not need to ask the user for broad runtime storage permissions in the manifest. The framework provides a unified interface across local storage and cloud providers: “Locally or remotely, the API is abstracting all the complexity for you, so you just consume it in the same way, whether it's on the device or remotely.”

Interactions are driven by system intents that display the built-in document picker: - `ACTION_OPEN_DOCUMENT`: Launches the system picker to let the user select a single file. - `ACTION_OPEN_DOCUMENT_TREE`: Prompts the user to grant access to an entire directory hierarchy. - `ACTION_CREATE_DOCUMENT`: Prompts the user to pick a destination folder and file name to save a new file.

Rezgui explains that access granted via these picker intents is temporary by default; it persists only until the device reboots. If an app needs long-term access, it must call `takePersistableUriPermission()` on the returned URI, while still handling cases where the underlying file might be deleted later by the user.

To attach a PDF to an email, the app fires `ACTION_OPEN_DOCUMENT`, adds `Intent.CATEGORY_OPENABLE` to ensure it only retrieves actual openable streams (filtering out virtual entries like contact or calendar cards), and sets the MIME type specifically to `application/pdf`. The returned URI can then be previewed using the `PdfRenderer` API before sending the message.

Conversely, to save an email attachment to local disk, the app uses `ACTION_CREATE_DOCUMENT`. This intent takes parameters similar to document opening, alongside an optional `EXTRA_TITLE` extra containing a default suggested file name, which the user can alter inside the system save dialog. Once selected, the app opens an output stream or writable file descriptor to write out the attachment bytes.

---

[33:12](https://www.youtube.com/watch?v=UnJ3amzJM94&t=1992s) Best Practices, Enterprise Access, and Wrap-Up

Rezgui outlines Google's vision for the storage ecosystem, stressing that the platform is committed to user privacy: “We want our ecosystem of applications to thrive with a privacy first approach.” Applications that have legitimate requirements for broad storage visibility—such as full backup solutions or standalone file managers—will have access to an unfiltered view of the `MediaStore` API. However, this level of access requires a privileged permission that must be submitted to and approved by Google Play via the Play Console, mirroring the strict review process already applied to SMS and call log permissions.

For everyday development, Rezgui warns against legacy file-handling habits: “But among our recommendations, one of them is do not use hardcoded path. The path may change between different versions, or the dile may be deleted or moved to a different folder.” Instead of assuming absolute file system locations, developers must combine the platform base content URIs with appended entity IDs.

Developers are encouraged to explore the official GitHub samples illustrating each Scoped Storage pattern and to test their code by setting `targetSdkVersion` to Android 10 (`29`) directly in Android Studio. Rezgui highlights that Scoped Storage remains an evolving API shaped heavily by feedback from the community: “If you have a specific use case that our API is not covering yet, please find a bug or an issue on our bug tracker to help us making a better Scoped Storage for you.”

Rezgui closes the session by inviting attendees to visit the sandbox booth to talk directly with product engineers. Displaying a slide with a survey URL on screen, he urges the audience with a smile: “You can take pictures. I will wait a quick moment there. I want to see phones.” After allowing attendees a moment to snap photos of the link, he thanks the crowd as the presentation concludes.

## Notable quotes > [33:32](https://www.youtube.com/watch?v=UnJ3amzJM94&t=2012s) We want our ecosystem of applications to thrive with a privacy first approach. — Yacine Rezgui

## Mentioned Roxanna Aliabadi, Zimuzo Ezeozue, Yacine Rezgui, Android, Android 10, Scoped Storage, Storage Access Framework, MediaStore, Google Play, Google Play Console, ContentResolver, PdfRenderer, Android Studio, GitHub

## Video description Plan overview and best practice guide to the new storage model in Android 10.

Presented by: Roxanna Aliabadi‎, Zimuzo Ezeozue, Yacine Rezgui

Android Dev Summit '19 all sessions playlist → https://goo.gle/ADS19allsessions

Subscribe to the Android Developers channel! → https://goo.gle/AndroidDevs

Check out the photo album → http://goo.gle/ADS19Photos

#AndroidDevSummit event: Android Dev Summit 2019; re_ty: Publish; product: Android - General; fullname: Roxanna Aliabadi, Yacine Rezgui, Zimuzo Ezeozue;

[Source](https://www.youtube.com/watch?v=UnJ3amzJM94)

中文简报

为分区存储做好准备(2019年 Android 开发者峰会) 演讲者详细介绍了 Android 10 向分区存储(Scoped Storage)的转变,解释了该平台如何通过限制宽泛的磁盘访问权限来保护用户隐私、防止孤立文件并沙盒化应用数据。针对早期变动引发的社区反馈,团队概述了计划在下一代 Android 版本中推行的关键调整,例如将 POSIX 文件路径桥接至 MediaStore、启用批量编辑确认对话框,以及为专用文件管理器建立受 Google Play 监管的访问路径。实操代码演示展示了如何通过 ContentResolver 查询媒体、借助 RecoverableSecurityException 处理权限挑战,以及在无需请求宽泛存储权限的情况下集成存储访问框架(SAF)进行文档选取。 Android 10 引入了分区存储以隔离应用数据并清理外部存储,以 Android 10 为目标平台的应用中有 98% 采用了该机制,且未声明临时退出该机制的旧版标记。 (5:23) 应用无需任何运行时权限即可向共享媒体合集(图片、视频、音频)和“下载”文件夹写入内容,但若要读取媒体合集之外的第三方文件,则需要使用存储访问框架(SAF)。 (2:05) 响应开发者的反馈,下一代 Android 版本将通过在底层将调用路由至 MediaStore,重新引入用于读取媒体的直接 POSIX 文件路径访问,并提供用于修改第三方文件的批量对话框。 (14:37) 需要宽泛文件系统访问权限的应用(如文件管理器和备份实用程序)将需要专用的“特殊应用访问权限”,并须通过 Google Play 的声明和审核流程。 (19:52)

Source quotes

[33:32] Yacine Rezgui: We want our ecosystem of applications to thrive with a privacy first approach.

Original transcript

[0:00] [MUSIC PLAYING] [0:06] ROXANNA ALIBADI: Hi. [0:06] My name is Roxanna, and I'm a product manager [0:09] on the Android Framework team. [0:10] And I'm joined by Zim and Yacine. [0:14] So last year, we introduced a new way [0:16] of thinking about storage on Android with Android 10. [0:21] We call this change Scope Storage. [0:24] And so today, we're going to talk more about those changes, [0:26] and we're going to talk about some new things [0:28] that we're thinking about to make these changes easier [0:31] for developers to adopt. [0:34] And at the end, Yacine is going to go [0:35] through some practical examples and best practices. [0:41] So first, I want to clarify what's meant by shared storage. [0:46] Every app has their own private directory in internal storage. [0:50] This is what you find at android/data/ your package [0:53] name. [0:54] And this is not visible to any other app with the storage [0:56] permission. [0:59] Then everything else is considered shared storage. [1:03] This includes the media collections and external app [1:06] directories on the SD card. [1:10] We find that about half of apps today [1:12] request the storage permission. [1:14] But in fact, the majority of these apps [1:16] don't really need such a broad view of storage. [1:19] They're trying to do simple things [1:21] like select an image file for a user to pick a profile [1:24] picture for a social app, or maybe to download an image [1:29] or a document from an email attachment. [1:34] We also find that when apps have such broad writing power, [1:37] they tend to leave files scattered on the disk. [1:40] And when the app is uninstalled, those files [1:42] are left behind, taking up space. [1:44] And when so many users are suffering from low disk space, [1:47] they can take all the space they can get. [1:52] So we thought about how we can reimagine storage on Android so [1:56] that apps can get the specific access they need [1:59] without getting such a broad reading [2:02] and writing power that they don't actually need. [2:05] So with Scope Storage, which we introduced with Android 10, [2:08] the idea is to compartmentalize storage [2:11] into specified collections and to limit the access [2:14] to broad storage. [2:18] So as we were designing it, we thought [2:19] of three basic principles that we wanted to follow. [2:22] The first is better attribution. [2:25] This means that the system knows which apps created which files. [2:29] This helps the user better manage their storage. [2:33] It also makes sure that when an app is uninstalled, [2:35] all of its content is also removed unless the user [2:38] explicitly wants it kept. [2:41] The next is protecting app data. [2:46] So as I mentioned before, internal app directories [2:49] have been private. [2:50] We also want to make sure that the external app [2:53] directories that are created on an SD card [2:55] are also not able to easily be read by other apps. [3:02] And of course, we want to protect our users' data. [3:05] Because when you download an image [3:07] from a private message or a PDF of your tax return, [3:11] you probably don't want every other app [3:13] on the device with the storage permission [3:15] to be able to read those files. [3:21] So as we considered these principles, [3:23] here are some of the key features [3:24] that we added for Scope Storage in Android 10. [3:29] The first is that every app has unrestricted access [3:33] to their own app directories. [3:35] Now, this is going to be both internal app directories [3:38] and external app directories. [3:40] So with Android 10, you don't need [3:41] to request a storage permission to be [3:43] able to write files to your own app directory on the SD card. [3:49] The next is that you have unrestricted access [3:52] to contribute files to media collections and to downloads. [3:56] We created a new downloads collection also [3:59] with Android 10. [4:01] So this way, if you want to save an image, music file, video, [4:06] or any other document, you can do so without any permission [4:09] as long as it's saved in the organized media collections. [4:15] The next change we made is that the storage permission [4:18] is redefined. [4:19] So instead of giving broad access to shared storage, [4:22] you actually just get access to organized media [4:24] collections-- the image, video, and audio collections. [4:31] We also believe that app location-- or sorry-- [4:34] media location metadata is private to the user [4:37] or sensitive to the user. [4:38] So we created a new permission called access media location [4:41] that apps will need to declare if they [4:43] want to see that location metadata on the image. [4:46] If they don't request this, that location metadata [4:48] will be stripped when the app reads the image file. [4:55] So in order to read any other type of file, [4:58] like a PDF or a document, apps now [5:00] need to use the system picker. [5:03] This is accessed using the Storage Access Framework. [5:08] Also, writing any files outside of the organized media [5:11] collections or your app directories [5:13] also requires using the system picker. [5:15] This makes sure that users can choose [5:17] exactly where on the disk they want the file stored. [5:23] So what happened in Android 10? [5:25] We introduced Scope Storage in one of the early beta releases [5:28] of Android 10, and we imposed those changes for all apps, [5:32] regardless of target SDK. [5:34] However, we had significant developer feedback [5:37] that these changes were very dramatic and very [5:39] difficult to make in such a short period of time. [5:45] So we introduced a flag that you can [5:47] declare in your manifest file. [5:49] It's called request legacy external storage. [5:53] If an app declares this flag in their manifest, [5:55] then the storage permission works [5:57] as it did on previous versions of Android. [6:02] Despite some of the concerns that we heard, [6:04] we're really happy to see that of all of the apps that [6:07] are currently targeting Android 10, 98% of them [6:10] don't request this flag. [6:12] This shows us that the changes we [6:14] introduced with Scope Storage are [6:17] acceptable to most developers. [6:19] However, we also understand that a lot of apps [6:23] have not started targeting Android 10 yet. [6:26] And we also are very conscious about the experience [6:29] of these 2%, and we want to really think [6:32] about how we can improve Scope Storage and add features [6:35] so that these changes are easier for developers to adapt. [6:39] So we're actually going to talk about some [6:41] of the developer feedback that we've gotten, [6:43] some of the basic themes. [6:47] The first is that the changes that we introduced with Android [6:50] 10 have a lack of support for using [6:53] file paths or native libraries. [6:58] Next, there are specific categories [7:00] of apps that really need access to broad storage. [7:03] For example, you can think of file managers [7:05] or backup and restore apps. [7:07] So these apps attempted to use the Storage Access Framework [7:11] APIs to get a broad view of shared storage. [7:14] However, the problem is that those APIs were not [7:17] intended to be used to get access to so many nested files. [7:22] So those developers reported performance issues. [7:26] And also, they complained about some [7:28] of the UI difficulty of having the user go and select [7:32] root folders in order to get this level of storage. [7:37] And also, now that we've changed the storage permission means, [7:41] the definition has become muddled. [7:43] So for some apps that are updated, [7:45] the storage permission actually means that they're [7:47] getting access to media. [7:49] And for other apps that are not updated, [7:51] it means they have broad access to storage. [7:53] And that can be confusing. [7:56] So we actually want to talk about some of the things [7:58] that we're thinking about in the next release. [8:00] And that's not something we normally [8:01] talk about at this event, but I think [8:02] it's really important to announce to developers what [8:05] we're working on so that as you're making changes [8:09] for Android 10, you don't make any changes [8:11] that you'll need to reverse as you release [8:14] the next version of Android. [8:17] So the first thing is we're doing an update [8:19] to the permissions UI. [8:20] So we fixed the problem before where [8:24] apps that are actually only getting access to media [8:26] seem like they're getting access to all of shared storage. [8:29] We're going to differentiate this to the user. [8:30] So the user will see a different permission UI based on [8:34] if that app is updated and using Scope Storage or not. [8:39] And next, we're working really hard [8:41] to enable file paths and native libraries for reading media. [8:45] And Zim is going to talk more about that. [8:50] We're also updating the APIs for modifying and deleting [8:53] media files that the app didn't create itself. [8:56] And that includes that we're creating a bulk option. [9:01] The next big change that we're making [9:03] is we're adding a special app access permission. [9:06] This is specifically for apps that [9:07] can demonstrate a need for broad access to shared storage [9:10] and will be whitelisted by Google Play. [9:15] We're also taking it a step further [9:16] and protecting those external app directories [9:20] and making sure that users can't select [9:21] those directories with the Storage Access Framework APIs. [9:28] And a big change that we're making [9:29] is that we're going to be enforcing this [9:31] based on target SDK. [9:33] Last year, we did say that we would be enforcing this [9:35] regardless of target SDK for all apps [9:37] on the next release of Android. [9:39] But really, we think that the best thing for the users [9:41] is to introduce these changes gradually. [9:45] And we also want to make sure that developers can really [9:47] take the time to design their apps to make sure [9:50] that they're making the changes for Scope [9:52] Storage in a responsible way. [9:56] Now I'll hand it over to Zim, who [9:57] will talk more about the changes introduced with Android 10 [10:00] and some of the new features that we're working on. [10:06] ZIMUZO EZEOZUE: Thank you, Roxy. [10:07] Now I'm going to dive into some more detail [10:09] about the changes we launched in Android 10 [10:12] as well the changes expected in the next Android release. [10:18] >From the earliest versions of Android, [10:19] we've always had the audio, the images, [10:22] and the video collections. [10:24] These collections are intended for sharing media files [10:26] with other apps. [10:30] In Android 10, we made a big change [10:32] to allow contributing to these collections [10:35] without any permissions. [10:37] Likewise, you can edit and delete media [10:39] files you contributed without any permissions. [10:43] This was to reduce the number of apps requesting unnecessarily [10:46] these storage permissions. [10:50] To read media files not created by your app, [10:53] you will need the read external storage permission. [10:56] The write external storage permission [10:57] will be deprecated in the next Android release, [11:00] and requesting it will really only give you [11:02] read access to media files. [11:05] Editing or deleting media files not contributed by your app [11:09] is just not possible without explicit user consent. [11:13] This is to give users full control [11:16] over when apps want to edit or delete media files, [11:20] like their important pictures. [11:24] In the next Android release, when you request the storage [11:27] permission at runtime, users will [11:30] see two different permissions strings [11:32] depending on the target SDK version of your app. [11:35] If you're targeting the next Android release, [11:38] users will see a new media permission string [11:40] requesting just access to media files in external storage. [11:44] However, if you're targeting any other release, [11:46] users will continue to see the old storage permission [11:49] string requesting broad access to the external storage. [11:52] This way, our users will understand how much [11:55] access your app is requesting. [12:01] So in Android 10, we launched a brand new downloads collection [12:04] for sharing non-media files with other apps. [12:08] Like the media collections, contributing to this collection [12:12] and editing or deleting non-media files you contributed [12:16] doesn't require any permissions. [12:21] However, unlike the-- however, unlike the media collection, [12:27] the read external storage permission [12:28] does not give you any access to non-media files contributed [12:32] by other apps. [12:34] To gain access, you will need to launch the system picker [12:37] with Storage Access Framework APIs. [12:40] This will allow the user to explicitly select [12:42] what files or directories you can have access to. [12:46] And if the user grants you access to a file, [12:48] this will be a full access. [12:50] So you can read, edit, or delete media files and non-media files [12:55] as you please without any additional consent. [12:58] This is to give our users full control [13:01] over when apps want to access non-media files that [13:04] are sensitive, so for instance, their bank statements. [13:11] Protecting user data is our top priority [13:14] on Android, which is why in Android 10, [13:16] we started restricting access to sensitive metadata contained [13:21] in media files, primarily location. [13:24] We can transparently strip these metadata [13:26] when your app is reading media files contributed [13:29] by other apps. [13:32] To access this sensitive metadata, [13:34] you can request the access media location permission. [13:38] This permission is not user visible in the Settings UI. [13:43] However, it is a runtime permission, [13:45] so you have to declare it in your manifest [13:47] and request it at runtime alongside the read [13:50] external storage permission. [13:53] Since this is a runtime permission, [13:55] there is no guarantee that you will always have access [13:58] to this permission even if you have the read external storage [14:01] permission. [14:02] This is especially true on enterprise devices [14:05] where a device policy client can modify or change permissions [14:12] requested by other apps. [14:16] If it is absolutely important for your app [14:18] that you always have the exact bytes of the file on disk, [14:21] you can use the MediaStore.setRequireOriginal [14:24] API. [14:25] This will ensure that you always have [14:27] the exact bytes of the file on disk [14:29] or receive an exception if reduction [14:31] would have otherwise occurred. [14:37] In Android 10, we locked down file path access [14:41] to the common directories. [14:42] This enabled us to deliver on our privacy objectives [14:45] of protecting the user. [14:48] However, after going through the developer feedback, [14:50] we saw that this required a lot of effort [14:52] from you to adopt straight away. [14:54] And in the next Android release, we [14:56] will likely do this work for you. [15:03] I must emphasize that all apps should still use the MediaStore [15:07] whenever possible. [15:08] However, we understand that there are a lot of apps [15:10] dependent on libraries written in C and C++ that only accept [15:15] file paths. [15:16] This really is the only case where [15:18] we expect you to write new code that uses file paths. [15:24] A useful implementation detail that may help [15:26] understand the tradeoffs between file paths [15:29] and the MediaStore is that under the hood, [15:32] file path requests or I/O requests using file paths [15:36] are delegated to the MediaStore. [15:39] You can think of the file or file path as a convenience API [15:42] to the MediaStore. [15:45] This means that there is some performance [15:47] impact of using file paths, and there is really [15:50] no feature benefits, hence our strong recommendation [15:54] to use the MediaStore directly. [15:59] Additionally, all the MediaStore enforcements also apply here. [16:04] Media must be created in the appropriate media [16:06] directories, so no music in the pictures directory, [16:09] for instance. [16:10] To access media files created by other apps, [16:13] you will need to request the read external storage [16:16] permission. [16:18] Location reduction while reading media files contributed [16:22] by other apps will still occur if you do not [16:26] have the access media location permission granted. [16:30] Also, creating non-media files must happen in the Downloads [16:34] directory, so you must create non-media files like PDFs [16:37] in the Downloads directory. [16:39] And also, reading non-media files created by other apps [16:43] will require the Storage Access Framework APIs. [16:47] Files created by your app will be attributed correctly, [16:51] so this will count towards your app's disk usage on the device. [16:59] The team has run lots of benchmarks [17:00] on sequential random read and write workloads. [17:04] The conclusion here is that there is certainly [17:06] some performance impact to using-- [17:08] implement file path requests and delegating it [17:12] to the MediaStore. [17:13] However, this is negligible in most cases, [17:16] especially at low I/O rates. [17:19] If you really care about performance, [17:21] you should measure your use cases [17:22] to see how much impact file access has [17:24] on your app's performance. [17:26] Alternatively, you can just use the MediaStore APIs directly, [17:29] and this is guaranteed to give you the best [17:30] performance in all cases. [17:35] And a bit more detail if you really [17:36] insist on using file paths. [17:38] Opens and the first reads after opening [17:40] the file are fairly expensive. [17:43] So if you're going to use file paths, [17:45] please try to avoid opening and closing the same file [17:47] multiple times. [17:49] We have seen some apps in the wild doing this, [17:51] and this can noticeably degrade I/O throughput and battery [17:54] performance. [17:57] If you are building an app that does heavy I/O-- [18:00] so in the order of, say, a few hundred megabytes per second-- [18:03] we would really love to hear from you, [18:05] so please come say hi at the sandbox. [18:11] In Android 10, we require user consent [18:15] to edit or delete media not contributed by your app. [18:18] To do this, you must use the MediaStore APIs [18:21] to trigger a dialog to request user consent. [18:25] If the user accepts, you will get a callback into your app, [18:28] and you can proceed to access the file either with file paths [18:31] or with the MediaStore APIs. [18:35] Note that you will not get a prompt with just the file [18:38] path access. [18:39] So without the prior explicit user grant with the MediaStore [18:43] APIs, trying to edit or delete files contributed [18:47] by other apps, so media files contributed by other apps, [18:50] will just fail. [18:54] In the next Android release, we are improving the user consent [18:57] flow for editing or deleting media introduced in Android 10. [19:01] So now you can batch multiple edit [? ordered ?] [19:04] requests in one dialog instead of popping [19:07] one dialog per request, as it was in the case of Android 10. [19:11] This should significantly improve the UX in your app [19:14] and was a popular request in the last release. [19:17] And we are very thrilled to deliver this to you. [19:21] You always have the option to copy files [19:24] to your Apps directory in external storage [19:28] and edit the copy, but we would only [19:30] recommend this for one-off edits and small-sized files [19:35] since we do not want to clutter our user's disk, [19:38] and the copied file will count against the app's disk usage. [19:44] Now I will hand back to Roxy to talk about more storage changes [19:47] in the next Android release. [19:52] ROXANNA ALIBADI: Thanks, Zim. [19:54] So as we mentioned, in order to read, edit, or delete [19:58] files that were not created by your app that aren't media [20:01] files, you're going to need to use the Storage Access [20:04] Framework APIs. [20:07] So the way-- so Storage Access Framework APIs have-- [20:10] we saw were used by some apps that [20:12] wanted to get broad access to shared storage. [20:15] And as I mentioned, that's not the intent of those APIs. [20:19] So in order to prevent this, we made some changes to the UX [20:24] when the intent ACTION_OPEN_DOCUMENT_TREE [20:27] is launched. [20:28] So ACTION_OPEN_DOCUMENT_TREE is an intent [20:30] specifically for an app to request an entire directory [20:34] that it wants read and write access to. [20:37] In the next version of Android, apps [20:39] will not be able to ask the user to select the root, anything [20:44] under android/data, or the Downloads directory. [20:48] Apps can still select individual files [20:51] from the Downloads directory. [20:53] It just can't select the entire directory. [21:00] We're also adding special app access [21:03] for apps that can truly demonstrate [21:04] a need for broad access to shared storage. [21:10] There are a limited number of use cases [21:12] that we believe can demonstrate this need. [21:14] A couple examples that we know of [21:16] are File Manager and backup and restore apps. [21:23] Only apps that can prove this need [21:24] will be granted this access. [21:27] In order to demonstrate it, you'll [21:29] need to submit a declaration form to Google Play, [21:32] to the Google Play Developer Console. [21:35] And only if whitelisted will your app [21:37] be able to be submitted, and then [21:39] you can ask the user for this special app access. [21:44] If you are whitelisted and the user [21:46] grants your app this access, you'll [21:48] get an unfiltered view of MediaStore. [21:50] That includes non-media files. [21:55] However, these apps will not get access [21:57] to external app directories. [22:01] This is, like we mentioned before, [22:02] which we believe that these directories should [22:04] be more protected. [22:08] I want to emphasize that this access will not [22:11] be granted for apps that simply want to create their own file [22:14] picking experience. [22:15] Those apps should use the system picker. [22:22] Now, we created the request legacy storage-- [22:25] request external legacy storage flag in Android 10 [22:28] as a response to developer feedback [22:30] for apps that need more time to adapt to Scope Storage. [22:34] However, in future versions of Android, [22:36] this flag will no longer be available. [22:39] So only apps that have the special app access [22:41] will be able to get a broad view of shared storage. [22:47] I also hope that we've demonstrated in this talk [22:49] that we're really responsive to developer [22:51] feedback on this topic. [22:53] So I really encourage you, even though we're not enforcing this [22:56] until the future version of Android, [22:59] that you try out all the Scope Storage changes [23:01] and you let us know about use cases [23:02] that you feel are not supported and should be. [23:08] I also want to remind developers that as you [23:11] move to target Android 10, if you have any files that [23:14] are in shared storage, like PDFs or media files that [23:19] are outside the organized directories, [23:20] you'll need to move them into your app storage. [23:24] Otherwise, if you target Android 10, [23:26] you will lose access to these files. [23:32] So now let's recap some of the features [23:35] of Scope Storage in Android 10 and some of the new features [23:38] that we've talked about. [23:41] First, media can be contributed without permission now. [23:46] Also, non-media files can be contributed to the Downloads [23:48] directory. [23:51] However, non-media files reading those files [23:53] will require using the system picker and the Storage Access [23:56] Framework APIs. [24:00] Apps now need to request permission [24:02] to see location metadata, images, and videos, [24:05] access media location. [24:10] In the next version of Android, we'll [24:11] be introducing file path access for reading media. [24:17] In the next version, we'll be updating the Media Modification [24:20] APIs, including a bulk option. [24:25] And we'll be restricting the Storage Access Framework [24:28] so that users cannot select specific-- [24:32] directories will give broad access [24:34] to shared storage or sensitive directories. [24:38] And there will be a special app access for select use cases [24:42] whitelisted by Google Play. [24:48] And all this will be enforced by target SDK. [24:54] Now I'll had it over to Yacine, who [24:55] will go through some practical examples. [24:59] YACINE REZGUI: Thanks, Roxy. [25:02] So as Roxy and Zim mentioned, we're [25:04] simplifying the developer experience on Scope Storage. [25:09] But with all these APIs, it may not [25:11] be easy to figure out which one you [25:13] should use in your application. [25:16] So let me sum up all of that with [? a ?] [? sample ?] that [25:19] you can have an idea of what to use. [25:23] Imagine a media player app. [25:25] It needs to get all the videos on the phone device [25:30] and be able to display and play them [25:33] whenever the user wants it. [25:35] For this, we will use the MediaStore API. [25:40] The advantage of it is to have all the files indexed [25:43] so it helps in terms of performance of discoverability. [25:50] We can get the files through the ContentResolver API, [25:54] and we can use advance query parameters like size, duration, [25:58] or resolution. [26:02] Finally, because we're accessing files created [26:05] by other applications, we need to add [26:07] the read external storage permission in our manifest. [26:14] So the MediaStore API is a contract [26:16] between the media provider and the application that use it. [26:21] We queried through the ContentResolver, which has [26:25] a similar API to an SQL query. [26:28] We choose the data we want with a projection, [26:31] filter it with some selected arguments, [26:36] and order it based on the selected columns. [26:40] For our query, in this case, we want [26:43] to have the ID column, the display name, duration, [26:47] and size. [26:49] Those columns are part of the MediaStore video columns [26:52] contract. [26:53] You can have the full list on the website on our web [26:57] documentation. [27:05] So for our selections argument, we [27:08] want to filter on videos equal to five minutes or longer. [27:12] And as the Duration column is in milliseconds, [27:15] we need to convert it to the right unit. [27:20] We attach all of those elements to [27:22] our query with the right MediaStore video content URI. [27:28] We also want to order it by the duration. [27:35] The query returns us a cursor to go through all the results. [27:40] We need to-- sorry. [27:42] My bad. [27:43] We need to get each column's index [27:46] to be able to get the content. [27:48] If the column doesn't exist, we get an exception. [27:53] We're caching the indexes here to avoid [27:55] having to fetch for each result for each row. [28:01] We loop through our cursor and get data for each column [28:05] based on its [? size. ?] Since we're [28:09] accessing the external content URI, from the MediaStore video [28:14] collection, we need to use the base URI [28:17] and append the ID of the video at the end of it. [28:20] That will get our content URI, and we can use it. [28:26] Finally, we get all the data, we can add to our list [28:29] and display it to the user. [28:33] Now for our second use case, let's imagine a photo feature [28:36] app. [28:37] You can create images as well as editing or deleting images [28:41] created by other applications. [28:44] For this, we will use again the MediaStore API. [28:48] Because, as mentioned, we're possibly [28:50] editing images from other applications, [28:53] we will need the READ_EXTERNAL_STORAGE [28:54] permission. [28:57] Whenever we'll edit or delete an image, [29:00] the OS will prompt a dialog to the user to get that content. [29:05] >From the next Android release, you [29:09] will be able to bulk all of those requests [29:11] within a single dialog. [29:15] Lastly, if you want to provide an enhanced experience based [29:19] on the location of where the photos were taken, [29:22] you need to add the access media allocation [29:26] to be able to get all the EXIF data of any file. [29:30] Remember that you have to double check if you still have access [29:33] to this media location. [29:35] You should not assume having it all the time. [29:40] To be able to prompt the dialog to the user, [29:43] we need first to append the file descriptor [29:45] on the write mode, which at the first time, initially, [29:50] it will throw us an exception, a recoverable security exception. [29:59] Within that exception data, there [30:01] is a pending intent that we need to send to the system [30:04] to be able to get the dialog. [30:07] Once the user [? counts and ?] given, [30:09] we can open again the file descriptor [30:11] and have finally access to it. [30:15] Now let's imagine another use case, [30:17] a productivity application, something like email, [30:20] for example. [30:21] We may want to write an email and attach a file to it, [30:24] any type of it. [30:25] It can be a PDF, a ZIP file, or something else. [30:29] For this, we will use the Storage Access Framework. [30:35] Whenever you need it, you don't actually [30:38] have to ask for permission. [30:41] You can use any files available on the user device [30:46] as well as using content from other content [30:48] providers like Google Drive. [30:51] Locally or remotely, the API is abstracting all the complexity [30:55] for you, so you just consume it in the same way, [30:58] whether it's on the device or remotely. [31:03] The UI is handled by an intent. [31:06] So here we need to use a specific intent [31:08] to be able to have the file picker. [31:10] To select a file, we need to use the ACTION_OPEN_DOCUMENT [31:14] intent. [31:15] And to select a folder, we need to use [31:18] ACTION_OPEN_DOCUMENT_TREE. [31:22] The access on the file is not granted all the time. [31:26] Until the user reboot, you still have access to it. [31:29] If you want to persist it, you need [31:30] to use takePersistableUriPermission [31:33] method. [31:34] With it, you will have always access to that file. [31:38] But you also need to check that this file hasn't [31:40] been deleted in the meantime. [31:45] Inside our productivity app, the first thing we will do [31:47] is to use that ACTION_OPEN_DOCUMENT. [31:51] In this case, we will set the category [31:53] to category openable, which means we will [31:56] get the openable entities-- [31:58] it means the files-- [32:00] to avoid not having the calendar of contact entries, [32:02] for example. [32:04] We set the write [? main ?] type. [32:06] In this case, we just want to have the application [32:08] PDF, which means the PDFs. [32:16] At this point, we can render the PDF, for example, [32:19] in our draft email just to show a preview to the user using [32:23] PDF Render API, for example. [32:25] And lastly, we can just send the email, [32:27] and having our whole experience. [32:31] A second example within our Gmail app [32:33] is the ability to save any attached files to an email [32:37] wherever the user want on device. [32:40] For this, we will use ACTION_CREATE_DOCUMENT intent. [32:44] It has similar parameters to the previous action we just [32:48] created with an extra one here, extra title where [32:51] we can put a default finding. [32:54] The user can still change that within the file saver UI. [33:00] Lastly, we can open the file descriptor on it [33:04] and just edit it on the write mode and add the content there. [33:12] We want our ecosystem of applications [33:14] to thrive with a privacy first approach. [33:18] If you provide backup of file management features, [33:23] you can get an unfiltered view of the MediaStore API. [33:28] It requires a special access permission [33:33] which needs to be approved in the Play Console [33:35] like SMS and core permissions. [33:44] We're here to help you getting ready for Scope Storage. [33:48] If you have any questions, come to talk to us at our sandbox [33:51] booth. [33:52] We will have the experts answering all your questions. [33:55] But among our recommendations, one of them [33:57] is do not use hardcoded path. [34:02] The path may change between different versions, [34:05] or the dile may be deleted or moved to a different folder. [34:09] You should not assume having that. [34:11] The main thing we advise you to use [34:13] is to mix the content URI with appended ID in the same way I [34:17] presented earlier. [34:19] You can check out all our code sample [34:21] on our GitHub, which highlights all the possible use [34:24] cases with scope storage. [34:27] And you can already test Android 10 SDK [34:30] by targeting it on Android Studio. [34:35] We shaped the features on Score Storage based on your feedback. [34:39] If you have a specific use case that our API is not [34:42] covering yet, please find a bug or an issue on our bug [34:46] tracker to help us making a better Scope Storage for you. [34:52] If you have any questions, again, [34:55] come to our sandbox booth. [34:57] It's an opportunity for you to have access [34:59] to so many engineers from the product team. [35:03] Also, to understand more of your own usage of Score Storage [35:07] and trying to understand how can we shape better the API, [35:10] please fill the survey line available there. [35:14] You can take pictures. [35:15] I will wait a quick moment there. [35:19] I want to see phones. [35:26] Thank you, everyone. [35:27] [MUSIC PLAYING]