# Storage ### Storage Principles #### App-Specific Requirements - Store files that are meant for our use only - Store files that we intend to share with other apps - e.g. taking a photo - Store private, primitive data - Config data, passwords, cookies & keys, etc. - Store private, structured data - text messages #### Mobile Storage Principles - Efficiency and sharing vs privacy and security - Limited storage capacity - Highly personal information stored - Lots of different data types stored on phone - Media - Images, videos, music > Access to the mail should be protected since this is sensitive user data. However, if a reference to an image attachment is given to an image viewer, that image viewer will not have permission to open the attachment since it has no reason to hold a permission to access all e-mail. ##### Storage Directories `/system` -> stores Android OS & libraries `/data` -> where user data is stored (every application is a user) `/mnt/sdcard` (symlinked as `sdcard`) -> *External* Storage ### Basic Logical Data Storage on Android ##### Different Volumes ###### Internal - Limited space for app-specific data - Reliable (not *removable*) - Soldered RAM ###### External - Lots of data - May (or may not) be physically removable ##### Different kinds of data - Data that is only meaningful for our app should use app-specific storage - Shareable media content should use shared storage so that other apps can access the content - Also called scoped storage ##### File-based abstractions - Shared preferences - File-based storage - SQLite database - Structured data, small binary blobs ![image-20220107004129910](img/ac.png) ## Internal File Storage Internal data storage is private to the app - Other apps (and the user) cannot access it - Kernel-enforced user perms - Removed on uninstall - Data is stored in files - `/data/data/com.example.project/files/` - Full path not accessible; `files/` becomes the chroot - This ensures we cannot traverse the directory upwards and gain access to other applications' files ##### Cache Files `/data/data/com.example.project/cache` `getCacheDir()` -> gets application’s file directory Programmer should manage the files - **May** be deleted when internal storage becomes full - **Will** be deleted when application is uninstalled - A *well-behaved* application will delete them when no longer in use - Recommended to use less than 1MB #### Shared Preferences - Stored on a per-application basis - e.g. saving config info (settings) - Should not be used for data transfer (use intents and binders instead) - Primitive data in key-value pairs - Can have multiple preference files per application ```xml light ``` ```java SharedPreferences settings = getSharedPreferences(CONFIG_STORAGE_NAME, 0); SharedPreferences.Editor editor = settings.editor; if (settings.getBoolean(MainActivity.CONFIG_THEME, false)) setTheme(...); else ... ``` #### External Storage *Legacy name* - Every Android device provides externally accessible storage (SD card) - Even phones without a physical SD card must have a **logical representation** of external storage - Most phones will have one storage device partitioned into `internal / external` - Phones must do this to conform to the Android API - *Private* Application files - *Internal* storage on the external partition - `getExternalFilesDir()` - `/sdcard/Android/data/com.example.project/` - *Public* general files - World reachable - Other apps can read and modify these files - Each *user* has their own *virtual* SD card - Can be mounted externally (and unmounted/disconnected) ##### Getting Access to External Storage - Should check state with `Enviroment.getExternalStorageState()` - It is a separate file system, potentially removable - `Environment.MEDIA_MOUNTED` - `Environment.MEDIA_MOUNTED_READ_ONLY` - Use `getExternalStoragePublicDirectory (String type)` to obtain file for the directory - Media is stored by type - Music in the music dir, etc. - Pass a type to obtain the subdirectory for that type ##### Getting Scoped storage access - To access files that other apps have created - We must have `READ_EXTERNAL_STORAGE` permission (in the manifest) - With this one permission, the app can do whatever (look at downloads, listen to music, look at pictures, etc.) - This is where scoped storage comes into play - The files must reside in the media collection (images/music/videos, etc.) - or request legacy storage `MANAGE_EXTERNAL_STORAGE` (before Android 11) - Apps only have access to - App-specific directory on external storage - Specific types of media that the app has created and contributed to well-defined collections - If the app takes a picture, it is allowed to store and look at that picture but not allowed to access pictures not taken by that app - You don't need to request perms to read/write images that we are writing to the MediaStorage # Android Databases When the data stored is logically structured, queries are needed to find it based on the structure. - Android provides local database support - Can run full SQL queries - Each app’s databases are local to it - `Database.db` stored in internal storage - Powered by SQLite #### Android and SQLite - Wrapped in two main classes - Database represented by `SQLiteDatabase` object - Allows us to run SQL queries on the database - `SQLiteOpenHelper` - Supports the application lifecycle - `SQLiteOpenHelper` -> `onCreate()` - Creates the database the **first time** it is called - This database will exist until the application is installed - `SQLiteOpenHelper` -> `onUpdate(int oldVer, int newVer)` - Changing the version number allows the database to be dropped and recreated - Create an instance of our `SQLiteOpenHelper` subclass - Get reference to `SQLiteDatabase` using - `getReadableDatabase()` - `getWriteableDatabase()` ##### Querying a Database `void execSQL()` -> used to execute SQL queries that don't return anything `query()` and `rawQuery()` - These return a Cursor object pointing to the results `Cursor rawQuery (String sql, String[] selectionArgs)` ###### Cursors - Provide random access to results of a query - Enable us to enumerate the rows returned by the query - `moveToFirst()`, `moveToNext()` - `getString(colIndex)`, `getInt(colIndex)` - Have a `close()` method to close the query when finished We can pass cursors to other applications ###### CursorLoader - A query may last some time - Database may be large - May be in a different process - Don’t block the main thread - `CursorLoader` - Populates views asynchronously - Auto-updating (deprecated) #### Data-Driven Views - *Connect* a cursor to a `CursorAdapter` and a `ListView` - Think mapping rows of a database to which entry in the list - Each row must have an ID field - `RecyclerView` - An optimised, flexible version of the above - Only creates views for visible data - As the user scrolls, more data is added - We can define our own adaptor ### Database Abstraction Abstraction of database architecture - Easier to update storage code - Expose column indices as static class variables - `c.getInt(0)` ✗ - `c.getInt(DBHelper.NAME)` ✓ - Helper methods keep database internals from *leaking* into other classes - Return a collection of results rather than the cursor - **Sanitise user inputs** - SQL injections still apply