# Content Providers - Storage Access to data is restricted to the app that owns it - Database is usually located in internal app-specific storage - If we want other apps to access our data, or we want to access other apps’ data, or we want to be notified when data has changed, we must use a content provider Content providers expose data / content to other applications in a structured manner - Fundamentally IPC via Binder and ashmem (Android shared memory) with a well-defined (database-like) interface #### System Content Providers Content providers manage data for: **Browser**: bookmarks, history **Call Log**: Telephone usage **Contacts**: Contact data, contacts for other apps, e.g. WhatsApp **Media**: Media metadata database **User Dictionary**: database for predictive spelling ###### Storage Access Framework Is an abstraction of *documents* - Restricted access to external storage - Enumerated by the system content object picker ![image-20220107180058110](img/af.png) A content provider is mostly used for making content available outside your application, as using it to get data is now done by the repository. ###### How to use it? - Create our own by sub-classing `ContentProvider` - Must add it in the manifest - Or add/query data via an existing content provider ### Data Model Very similar to a relational database table - A collection of records - Support for read/write - Support for typical database operations - CRUD - **C**reate **R**ead **U**pdate **D**elete Records are stored in rows, with each column providing different data fields - Each record has a numeric id (in the field ID) that uniquely identifies it - Tables exposed via URI - This is a further abstraction ![image-20220107180837589](img/ag.png) Applications query the content provider, which maps the requests to the underlying database. This can be SQLite or Room (doesn’t really matter to the application) ### Querying a Content Provider Content Providers **identify data** sets through **URIs** - `content://authority/path/id` - **content**: Data managed by a content provider - **authority**: ID for the Content provider - A fully qualified class name, e.g. `com.example.project` - **path**: 0 or more segments indicating the subset of data to be requested - e.g. table name - A RESTful resource philosophy - **id**: specific record (row) being accessed `/email/2021/Nov/17` -> would retrieve all emails received on Nov 17th 📅 ###### Content Resolver - Manages and supports content provider access - How to service a request for content - Similar to `ServiceManager` - Enables Content Providers to be used across multiple applications - Can observe a content provider to be informed of real-time modifications - e.g. `contentResolver` monitors the path and can notify if a new email pops up ✉ Full URI: `ContactsContract.Contact.CONTENT_URI = "content://com.android.contacts/contacts/"` `ContentResolver.query(...)` - Returns a cursor instance for accessing results - Cursor is a pointer to a `cursorWindow` - A read-only reference to shared memory - Allocated by ashmem - Retrieved via Binder - Max `CursorWindow` size is 2 Mb ###### Example of Querying Contacts - To access / modify requires a permission - `android.permission.READ_CONTACTS` - `android.permission.WRITE_CONTACTS` - Contacts has 3 components - Data - Rows (mime-typed) that can hold personal info - Raw Contacts - A contact for a given person from a given system - Gmail contact, Facebook contact, etc. - Associated with data entries - Contacts - Aggregated raw contacts - Single view of a *person* ##### Modifying a Content Provider `Uri insert (Uri uri, ContentValues values)` Returns the URI of the newly inserted item `int update(Uri uri, ContentValues values, String where, String[] selectionArgs)` ###### Parameters **uri**: the *table* we want to modify **content values**: values for the new row or key/value pairs where the key is the column name #### Creating a content Provider - Implement a storage system for the data - Structured data, can be SQLite or Room - Media & blobs - Implement a content provider - query, add, update, insert, etc. - onCreate - When content provider is instantiated, needs to instantiate the internal storage (create the table) - getType - single items, multiple items, mime type - Tell Android we are a provider - Declare in the manifest #### Contract - Defines metadata pertaining to the provider - Constant definitions that are exposed to developers via a compiled .jar file - Authority - URI - Meta-data - Column names #### URI Matching All of these methods take a URI as the first parameter - The object will need to parse it to know what to return `android.content.UriMatcher` - Provides mapping between abstraction of contract class to concrete db implementation - Does the calling app want all the data from the table or just a row? - `content://authority/tablename/` - whole table - `content://authority/tablename/1` - row - Or a virtual table (joins across various underlying resources)