Differences

This shows you the differences between two versions of the page.

Link to this comparison view

smd:laboratoare:06 [2021/04/21 19:50]
adriana.draghici [Android storage model]
smd:laboratoare:06 [2021/05/20 21:30] (current)
adriana.draghici [Shared preferences]
Line 20: Line 20:
  
 <note important>​Android API Level 29 introduced important changes to how storage is accessed, driven by the need for increased privacy. <note important>​Android API Level 29 introduced important changes to how storage is accessed, driven by the need for increased privacy.
-It provided Scoped Storage([[https://​developer.android.com/​training/​data-storage#​scoped-storage|documentation]][[https://​www.raywenderlich.com/​9577211-scoped-storage-in-android-10-getting-started|tutorial]]). Api Level 30 also introduced some updates related to storage, check [[https://​developer.android.com/​about/​versions/​11/​privacy/​storage|this link]] for some information about them. </​note>​+It provided ​**Scoped Storage** ([[https://​developer.android.com/​training/​data-storage#​scoped-storage|documentation]][[https://​www.raywenderlich.com/​9577211-scoped-storage-in-android-10-getting-started|tutorial]]). Api Level 30 also introduced some updates related to storage, check [[https://​developer.android.com/​about/​versions/​11/​privacy/​storage|this link]] for some information about them. </​note>​
  
 ====Internal Storage==== ====Internal Storage====
Line 49: Line 49:
       * accessing public external files requires the permissions       * accessing public external files requires the permissions
       * accessing private external files does not require the permissions from API Level 18 (Android 4.4 - KitKat).       * accessing private external files does not require the permissions from API Level 18 (Android 4.4 - KitKat).
-   ​* ​**__Security tips:__**+<note important>​**__Security tips:__**
      * validate the data read from external storage      * validate the data read from external storage
      * encrypt sensitive data stored in external storage      * encrypt sensitive data stored in external storage
      * decide whether the data should be persisted after the app is installed or not.      * decide whether the data should be persisted after the app is installed or not.
      * ask for the permissions at runtime, preferably showing a custom message informing the user why do you need those permissions.      * ask for the permissions at runtime, preferably showing a custom message informing the user why do you need those permissions.
 +</​note>​
 **How-to:** **How-to:**
    * Declare the permissions in the manifest (if needed)    * Declare the permissions in the manifest (if needed)
    * Obtain the path using one of the following methods provided by the [[https://​developer.android.com/​reference/​android/​os/​Environment.html|Environment]] class or Context classes:    * Obtain the path using one of the following methods provided by the [[https://​developer.android.com/​reference/​android/​os/​Environment.html|Environment]] class or Context classes:
-     * [[https://​developer.android.com/​reference/​android/​os/​Environment.html#​getExternalStoragePublicDirectory(java.lang.String)|Environment.getExternalStoragePublicDirectory]] - returns the path to the public external directory 
      * [[https://​developer.android.com/​reference/​android/​content/​Context.html#​getExternalFilesDir(java.lang.String)|Context.getExternalFilesDir()]] - returns the path to the private external directory      * [[https://​developer.android.com/​reference/​android/​content/​Context.html#​getExternalFilesDir(java.lang.String)|Context.getExternalFilesDir()]] - returns the path to the private external directory
      * [[https://​developer.android.com/​reference/​android/​content/​Context.html#​getExternalFilesDirs(java.lang.String)|Context.getExternalFilesDirs]] - returns an array of paths to the external directories (e.g. you can have two directories if an sd card is present).      * [[https://​developer.android.com/​reference/​android/​content/​Context.html#​getExternalFilesDirs(java.lang.String)|Context.getExternalFilesDirs]] - returns an array of paths to the external directories (e.g. you can have two directories if an sd card is present).
Line 66: Line 65:
  
 <code Java> <code Java>
 + // Code working on versions < Q (Android10 aka API Level 29)
 +
  ​String path = Environment.getExternalStorageDirectory().toString();​  ​String path = Environment.getExternalStorageDirectory().toString();​
  File file = new File(path, "​image.png"​);​  File file = new File(path, "​image.png"​);​
Line 78: Line 79:
 </​code>​ </​code>​
  
-[[https://developer.android.com/training/​data-storage/files.html#WriteExternalStorage|Code tutorial]]+From Android 10 you need to use ContentResolver like in these examples: ​[[https://www.raywenderlich.com/10217168-preparing-for-scoped-storage|Creating a new file]], [[https://​stackoverflow.com/​questions/​56468539/​getexternalstoragepublicdirectory-deprecated-in-android-q/​57649669#57649669|ContentResolver SO thread]]
    
  
Line 92: Line 93:
 sharedPref = this.getSharedPreferences("​mysettings",​ Context.MODE_PRIVATE);​ sharedPref = this.getSharedPreferences("​mysettings",​ Context.MODE_PRIVATE);​
 // or // or
-sharedPref = PreferenceManager.getDefaultSharedPreferences(context);​+sharedPref = PreferenceManager.getDefaultSharedPreferences(context); ​//!!! recently deprecated in API level 29
 </​code>​ </​code>​
  
Line 128: Line 129:
 ==== Task 0 - Init ==== ==== Task 0 - Init ====
  
-Create a new Android application project. ​Download ​the lab archive and use its content, or start with your own UI design.+Create a new Android application project. ​You can download ​the lab archive and use its layout, or start with your own UI design.
  
 ==== Task 1 - Runtime permission check ==== ==== Task 1 - Runtime permission check ====
Line 159: Line 160:
 Provide the functionality from tasks 1 and 2 using internal storage instead of external. Provide the functionality from tasks 1 and 2 using internal storage instead of external.
   * You can choose to store the file using one of the methods described in the [[smd:​laboratoare:​06##​internal_storage|Internal Storage]] section. ​   * You can choose to store the file using one of the methods described in the [[smd:​laboratoare:​06##​internal_storage|Internal Storage]] section. ​
-  * Log the path of the file, try to access it from the command line.+  * Log the path of the file, try to access it from the command line (adb shell).
  
 ==== Task 5 - Shared preferences ==== ==== Task 5 - Shared preferences ====
Line 169: Line 170:
   * When the user selects an item from the spinner, store it as a shared preference. Use [[https://​developer.android.com/​reference/​android/​widget/​AdapterView.html#​setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)|setOnItemSelectedListener]].   * When the user selects an item from the spinner, store it as a shared preference. Use [[https://​developer.android.com/​reference/​android/​widget/​AdapterView.html#​setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)|setOnItemSelectedListener]].
   * When the user clicks Download, use an external or internal path, depending on the value stored in the shared preferences. If the value is "​Undefined",​ show a toast telling the user to choose a type of storage.   * When the user clicks Download, use an external or internal path, depending on the value stored in the shared preferences. If the value is "​Undefined",​ show a toast telling the user to choose a type of storage.
 +
 +<spoiler Example >
 +<code java>
 +    private String getStorageType() {
 +        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);​
 +        return sharedPref.getString(getString(R.string.storage_type_key),​ "​undefined"​);​
 +    }
 +
 +    private void storeStorageType(String type)
 +        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();​
 +        editor.putString(getString(R.string.storage_type_key),​ type);
 +        editor.apply();​
 +    }
 +
 +    private class StorageTypeSelectedListener implements AdapterView.OnItemSelectedListener {
 +
 +        @Override
 +        public void onItemSelected(AdapterView<?>​ adapterView,​ View view, int i, long l) {
 +            String selectedItem = adapterView.getItemAtPosition(i).toString();​
 +            Log.d(TAG, "​Selected storage type: " +  selectedItem);​
 +            storeStorageType(selectedItem);​
 +        }
 +
 +        @Override
 +        public void onNothingSelected(AdapterView<?>​ adapterView) {
 +        }
 +    }
 +    </​code>​
 +</​spoiler>​
   ​   ​
 Image manipulation code snippets: Image manipulation code snippets:
Line 195: Line 225:
 ===== Resources & Useful Links===== ===== Resources & Useful Links=====
   * [[https://​developer.android.com/​guide/​topics/​data/​data-storage|Android Data Storage documentation]]   * [[https://​developer.android.com/​guide/​topics/​data/​data-storage|Android Data Storage documentation]]
-  * [[https://​developer.android.com/​training/data-storage/files.html|Save files on device ​storage]] +  * [[https://​developer.android.com/​about/versions/​11/​privacy/storage|Storage updates in Android 11]] 
-  * {{lab6-skel.zip|}}+  * {{lab6_skel.zip|}}
  
smd/laboratoare/06.1619023831.txt.gz · Last modified: 2021/04/21 19:50 by adriana.draghici
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0