Security of applications' data comes also from the sandboxing mechanism used by the Android system. Using it, not only the executed code is isolated from other apps, but also the data.
The application-specific storage is split into internal storage and external storage. The difference between them is in the access control. A common mistake is to assume that external storage refers to SD cards. It is a space that can include the phones' storage and also an SD card.
The storage accessible only to your app also includes:
For sharing data to external apps, you can use one of the main Android components: ContentProviders. For files, this component is extended by the FileProvider.
How-to:
Context
class:WRITE_EXTERNAL_STORAGE
or READ_EXTERNAL_STORAGE
permissions (declaring the write permission automatically grants the read permission as well). The next Android version, Q, deprecates these.
Android provides the MediaStore that provides your app's external files to the other apps. See the next code snippet in which we store an image.
// Code working on versions < Q (Android10 aka API Level 29) String path = Environment.getExternalStorageDirectory().toString(); File file = new File(path, "image.png"); // ... some code that writes stuff to the image ... MediaStore.Images.Media.insertImage( context.getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
From Android 10 you need to use ContentResolver like in these examples: Creating a new file, ContentResolver SO thread
The Android framework offers an API for storing key-value pairs accessible only to your app. Usually they are used for persisting settings (user preferences).
The key-value pairs are stored in files. You can use one or several files, depending on your app's design. In order to access them, you need to obtain a SharedPreference object using methods provided by the Context class. These files can also be specific to an activity.
// In this example we are in MainActivity SharedPreferences sharedPref = this.getPreferences(MODE_PRIVATE); // or sharedPref = this.getSharedPreferences("mysettings", Context.MODE_PRIVATE); // or sharedPref = PreferenceManager.getDefaultSharedPreferences(context); //!!! recently deprecated in API level 29
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit(); editor.putString("my_key", "my_value"); editor.putBoolean("my_bool", true); editor.putInt("my_int", 0); // Must save them! editor.apply(); //async write to disc // or use editor.commit(); //immediately writes to disc, avoid using it from UI thread. //obtain values: sharedPref.getString("my-key", "default-value");
For securing these preferences through encryption we can implement this mechanism using Android's KeyStore API or use a third-party library like Secure Preferences.
Create an app that can download an image from a given location, store it and show it to the user.
Each task is 2p.
Create a new Android application project. You can download the lab archive and use its layout, or start with your own UI design.
Add runtime permission checks when writing and reading the files from external storage (internal storage does not require permissions)
WRITE_EXTERNAL_STORAGE
and READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
in the manifestWhy? These permissions are considered dangerous, and since Android 6 (API23) they need to be requested at runtime for the user to approve them. This restriction has been imposed because such permissions target sensitive user info, and malicious apps requested them from the user at install time, the users just accepted them without reading properly. In this way, if an app wants to access external storage, send sms, use camera etc, it needs to prompt the user to grant the permission. A list of such permissions can be found here.
Implement a button listener which triggers an image download from a given URL and stores it on external storage.
adb shell
).Implement a button listener which loads the image from external storage and displays it in an ImageView.
Provide the functionality from tasks 1 and 2 using internal storage instead of external.
Use shared preferences for storing the preferred storage type (external/internal) for the image downloaded in the previous tasks.
Image manipulation code snippets:
// to obtain a Bitmap object from an InputStream BitmapFactory.decodeStream(input); // to save a Bitmap object in an OutputStream bitmap.compress(compressFormat, compressionRate, outputStream); // to read a Bitmap from a file Bitmap myBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); // to resize a Bitmap float scaleWidth = ((float) newWidth) / bitmap.width; float scaleHeight = ((float) newHeight) / bitmap.height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap bitmap2 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, false);