Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What’s New in Shared Storage

What’s New in Shared Storage

- 2019년 7월 16일 Google I/O Extended 2019 수원
- 2019년 6월 22일 Google I/O Extended 2019 인천
위 행사들에서 발표한 자료입니다.

안드로이드 Q에서 새로운 저장소 권한 모델을 발표하였습니다. Q부터 완전히 바뀌는 안드로이드 공용 저장소 시스템을 소개합니다.

Seungmin 마량

June 22, 2019
Tweet

More Decks by Seungmin 마량

Other Decks in Programming

Transcript

  1. ݾର 1. Storage ࠂण 2. Storage in Q 3. Storage

    Access Framework (SAF) 4. Scoped Mode 5. ੿ܻ
  2. Android 9 Storage Internal Storage 1. Read / Write ӂೠ

    হ੉ оמ 2. জ ࢏ઁೞݶ ੷੢ࣗ ౵ੌٜ ࢎۄ૗ 3. ఋ জীࢲ Read / Write ࠛоמ
  3. Android 9 Storage Internal Storage 1. Read / Write ӂೠ

    হ੉ оמ 2. জ ࢏ઁೞݶ ੷੢ࣗ ౵ੌٜ ࢎۄ૗ 3. ఋ জীࢲ Read / Write ࠛоמ ఋ জীࢲ ੽Ӕೞݶ উغח জ ؘ੉ఠ
  4. Android 9 Storage External Storage of MINE 1. Read /

    Write ӂೠ হ੉ оמ 2. জ ࢏ઁೞݶ ੷੢ࣗ ౵ੌٜ ࢎۄ૗ 3. ఋ জীࢲ Read / Write оמ
  5. Android 9 Storage External Storage of MINE 1. Read /

    Write ӂೠ হ੉ оמ 2. জ ࢏ઁೞݶ ੷੢ࣗ ౵ੌٜ ࢎۄ૗ 3. ఋ জীࢲ Read / Write оמ ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ
  6. Android 9 Storage External Storage of NOT MINE 1. Read

    / Write ӂೠ হ੉ ࠛоמ 2. জ ࢏ઁೞݶ ੷੢ࣗ ౵ੌٜ উࢎۄ૗ 3. ఋ জীࢲ Read / Write оמ Environment .getExternalStorageDirectory()
  7. Android 9 Storage External Storage of NOT MINE 1. Read

    / Write ӂೠ হ੉ ࠛоמ 2. জ ࢏ઁೞݶ ੷੢ࣗ ౵ੌٜ উࢎۄ૗ 3. ఋ জীࢲ Read / Write оמ Environment .getExternalStorageDirectory() ఋ জ ߂ ҕਊ ؘ੉ఠ
  8. 1. Internal Storage • ఋ জীࢲ ੽Ӕೞݶ উغח জ ؘ੉ఠ

    2. External Storage • ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ • ఋ জ ߂ ҕਊ ؘ੉ఠ Android 9 Storage
  9. Android 9 Storage sdcard ী ૒੽ Read/Write 1. Internal Storage

    • ఋ জীࢲ ੽Ӕೞݶ উغח জ ؘ੉ఠ 2. External Storage • ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ • ఋ জ ߂ ҕਊ ؘ੉ఠ
  10. Storage in Q - 3ਗ஗ (1) File੉ Owner Appਸ উ׮

    জ ࢏ઁ द MediaStore ৻ ࣗࣘ ౵ੌ ࢏ઁ ੷੢ࣗ ӂೠ ੓যب ఋ জ੄ ౵ੌ ੽Ӕ ઁೠ
  11. झ݃౟ೞѱ ࢎਊ੗ ؘ੉ఠ ҕਬ ౵ੌ ઙܨী ٮۄ ӂೠ ࣁ࠙ച জীࢲ

    ࢤࢿ/׮਍۽٘ೠ ౵ੌী ࢎਊ੗о যڃ জਵ۽ ঱ઁ ੽Ӕೞח૑ ঎ Storage in Q - 3ਗ஗ (3)
  12. Storage in Q 1. Internal Storage • ӝઓҗ زੌ 2.

    MediaStore • ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ 3. MediaStore.Downloads • ҕਊ ؘ੉ఠ. SystemPicker ా೧ࢲ ੽Ӕ.
  13. Storage in Q 1. Internal Storage • ӝઓҗ زੌ 2.

    MediaStore • ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ 3. MediaStore.Downloads • ҕਊ ؘ੉ఠ. SystemPicker ా೧ࢲ ੽Ӕ. SAF ా೧ Read/Write *Storage Access Framework
  14. Storage in Q 1. Internal Storage • ӝઓҗ زੌ 3.

    MediaStore.Downloads • ҕਊ ؘ੉ఠ. SystemPicker ా೧ࢲ ੽Ӕ. 2. MediaStore • ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ SAF ా೧ Read/Write
  15. Storage in Q MediaStore 1. Read / Write ӂೠ হ੉

    оמ. জҗ োѾغয ੓਺ 2. জ ࢏ઁೞݶ ౵ੌٜ উࢎۄ૗. োѾ Րয૗ 3. োѾ੉ Րয૓ MediaStoreח ఋ জ੄ MediaStore৬ ݃ଲо૑. 4. ఋ জীࢲ Read / Write द ੷੢ࣗ ӂೠ ৻ ౵ੌઙܨ ੽Ӕ ӂೠ ೙ਃ
  16. • ࢎਊ੗ীѱ ഒۆਸ ઴ ࣻ ੓ח ؘ੉ఠ MediaStore ੉۠ ؘ੉ఠח

    উظਃ! ex) চߧই౟, झ౭ழ৬ э਷ জ ղ ܻࣗझ
  17. Write MediaStore // Create a new image in the user's

    collection val values = ContentValues().apply { put(MediaStore.Images.Media.RELATIVE_PATH, “Pictures/Maryang Album/“) put(MediaStore.Images.Media.DISPLAY_NAME, name) put(MediaStore.Images.Media.MIME_TYPE, “image/jpeg") put(MediaStore.Images.Media.IS_PENDING, 1) } val resolver = context.contentResolver val collection = MediaStore.Images.Media .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val item = resolver.insert(collection, values)
  18. Write MediaStore ౵ੌ ࢤࢿ // Create a new image in

    the user's collection val values = ContentValues().apply { put(MediaStore.Images.Media.RELATIVE_PATH, “Pictures/Maryang Album/“) put(MediaStore.Images.Media.DISPLAY_NAME, name) put(MediaStore.Images.Media.MIME_TYPE, “image/jpeg") put(MediaStore.Images.Media.IS_PENDING, 1) } val resolver = context.contentResolver val collection = MediaStore.Images.Media .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val item = resolver.insert(collection, values)
  19. // Create a new image in the user's collection val

    values = ContentValues().apply { put(MediaStore.Images.Media.RELATIVE_PATH, “Pictures/Maryang Album/“) put(MediaStore.Images.Media.DISPLAY_NAME, name) put(MediaStore.Images.Media.MIME_TYPE, “image/jpeg") put(MediaStore.Images.Media.IS_PENDING, 1) } val resolver = context.contentResolver val collection = MediaStore.Images.Media .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val item = resolver.insert(collection, values) Write MediaStore ౵ੌ ࢤࢿ
  20. // Create a new image in the user's collection val

    values = ContentValues().apply { put(MediaStore.Images.Media.RELATIVE_PATH, “Pictures/Maryang Album/“) put(MediaStore.Images.Media.DISPLAY_NAME, name) put(MediaStore.Images.Media.MIME_TYPE, “image/jpeg") put(MediaStore.Images.Media.IS_PENDING, 1) } val resolver = context.contentResolver val collection = MediaStore.Images.Media .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val item = resolver.insert(collection, values) Write MediaStore ౵ੌ ࢤࢿ
  21. // Write bitmap into pending image output stream resolver.openOutputStream(item).use {

    stream -> bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream) } // Now that we're finished, reveal to other apps values.clear() values.put(MediaStore.Images.Media.IS_PENDING, 0) resolver.update(item, values, null, null) Write MediaStore ౵ੌ ੑ۱
  22. Write MediaStore ౵ੌ ੑ۱ // Write bitmap into pending image

    output stream resolver.openOutputStream(item).use { stream -> bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream) } // Now that we're finished, reveal to other apps values.clear() values.put(MediaStore.Images.Media.IS_PENDING, 0) resolver.update(item, values, null, null)
  23. Read MediaStore // Find images (both published and pending) val

    collection = getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val collectionWithPending = MediaStore.setIncludePending(collection) resolver.query(collectionWithPending).use { // Get a specific media item uri ContentUris.withAppendedId( collection, it.getLong(it.getColumnIndex(ImageColumns._ID)) ) }.let { // Open a specific media item resolver.openFileDescriptor(Uri.parse(it), "w").use { // ... do something } }
  24. Read MediaStore // Find images (both published and pending) val

    collection = getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val collectionWithPending = MediaStore.setIncludePending(collection) resolver.query(collectionWithPending).use { // Get a specific media item uri ContentUris.withAppendedId( collection, it.getLong(it.getColumnIndex(ImageColumns._ID)) ) }.let { // Open a specific media item resolver.openFileDescriptor(Uri.parse(it), "w").use { // ... do something } }
  25. Read MediaStore // Find images (both published and pending) val

    collection = getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val collectionWithPending = MediaStore.setIncludePending(collection) resolver.query(collectionWithPending).use { // Get a specific media item uri ContentUris.withAppendedId( collection, it.getLong(it.getColumnIndex(ImageColumns._ID)) ) }.let { // Open a specific media item resolver.openFileDescriptor(Uri.parse(it), "w").use { // ... do something } }
  26. MediaStore ׮ܖӝ - ఋ জ • ۠ఋ੐ ӂೠ ೙ਃೣ •

    ӂೠ ੓ਵݶ query() оמ • Read / Writeח ӂೠ ੓যب RecoverableSecurityException ؍૗ update(), delete(), openFileDescriptor() (۠ఋ੐ ӂೠҗ ࠺तೞѱ दझమ Dialogܳ ڸਕ ౵ੌী ؀೧ Write ӂೠਸ ঳ח׮)
  27. Access Other App’s MediaStore try { resolver.openFileDescriptor(Uri.parse(it), "w").use { //

    ... do something } } catch (e: RecoverableSecurityException) { AlertDialog.Builder(context) .setMessage(e.userMessage) .setPositiveButton(e.userAction.title) { try { e.userAction.actionIntent.send() } catch (ignored: PendingIntent.CanceledException) { } } .setNegativeButton("ஂࣗ", null) .show() }
  28. Access Other App’s MediaStore try { resolver.openFileDescriptor(Uri.parse(it), "w").use { //

    ... do something } } catch (e: RecoverableSecurityException) { AlertDialog.Builder(context) .setMessage(e.userMessage) .setPositiveButton(e.userAction.title) { try { e.userAction.actionIntent.send() } catch (ignored: PendingIntent.CanceledException) { } } .setNegativeButton("ஂࣗ", null) .show() }
  29. Access Other App’s MediaStore try { resolver.openFileDescriptor(Uri.parse(it), "w").use { //

    ... do something } } catch (e: RecoverableSecurityException) { AlertDialog.Builder(context) .setMessage(e.userMessage) .setPositiveButton(e.userAction.title) { try { e.userAction.actionIntent.send() } catch (ignored: PendingIntent.CanceledException) { } } .setNegativeButton("ஂࣗ", null) .show() }
  30. Access Other App’s MediaStore try { resolver.openFileDescriptor(Uri.parse(it), "w").use { //

    ... do something } } catch (e: RecoverableSecurityException) { AlertDialog.Builder(context) .setMessage(e.userMessage) .setPositiveButton(e.userAction.title) { try { e.userAction.actionIntent.send() } catch (ignored: PendingIntent.CanceledException) { } } .setNegativeButton("ஂࣗ", null) .show() }
  31. Access Other App’s MediaStore try { resolver.openFileDescriptor(Uri.parse(it), "w").use { //

    ... do something } } catch (e: RecoverableSecurityException) { AlertDialog.Builder(context) .setMessage(e.userMessage) .setPositiveButton(e.userAction.title) { try { e.userAction.actionIntent.send() } catch (ignored: PendingIntent.CanceledException) { } } .setNegativeButton("ஂࣗ", null) .show() } അ੤ ߬ఋীࢲח ੜ ز੘ೞ૑ ঋ਺
  32. ҕਊҕр ੽Ӕ startActivityForResult( Intent(Intent.ACTION_OPEN_DOCUMENT), REQUEST_CODE_READ ) override fun onActivityResult() {

    val result: Uri = resultIntent.data val pickedFile: DocumentFile = DocumentFile.fromSingleUri(this, result) }
  33. Write MediaStore.Downloads // Create a new image in the user's

    collection val values = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, name) put(MediaStore.Images.Media.MIME_TYPE, “image/jpeg") put(MediaStore.Images.Media.IS_PENDING, 1) } val resolver = context.contentResolver val collection = MediaStore.Downloads .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val item = resolver.insert(collection, values)
  34. Android 9 Storage sdcard ী ૒੽ Read/Write 1. Internal Storage

    • ఋ জীࢲ ੽Ӕೞݶ উغח জ ؘ੉ఠ 2. External Storage • ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ • ఋ জ ߂ ҕਊ ؘ੉ఠ
  35. Storage in Q 1. Internal Storage • ӝઓҗ زੌ 2.

    MediaStore • ఋ জীࢲ ੽Ӕ੉ ೙ਃೠ জ ؘ੉ఠ 3. MediaStore.Downloads • ҕਊ ؘ੉ఠ. SystemPicker ా೧ࢲ ੽Ӕ. SAF ా೧ Read/Write *Storage Access Framework
  36. জ ղীࢲ݅ ࢎਊೠ׮ݶ? Internal Storage۽ ޷ܻ ৤ѹفࣁਃ ݃੉Ӓۨ੉࣌ ఋ জ

    ౵ੌী ੽Ӕ੉ ೙ਃ೧ਃ! SAF۽ ੽Ӕೞࣁਃ ҅ࣘ ੽Ӕ೧ঠ ೠ׮ݶ Internal Storage۽ ৤ѹفࣁਃ ఋ জী ࠁৈઉঠ ೧ਃ Ӓ؀۽ فযب ҡଳইਃ (ղо ੽Ӕೡ ٸ ೠߣ ӂೠਸ ਃ୒ೡ ࣻ ੓਺) ✅ ✅ ✅
  37. Reference Google I/O 2019 Shared Storage ৔࢚ Google ޙࢲ Android

    Q privacy change: Scoped storage নଲࢳש Scoped Storage ࠶۽Ӓ উݺ਌ש Shared Storage ߊ಴੗ܐ ࢠ೒௏٘ ۨನ૑షܻ