11package de.markusfisch.android.binaryeye.fragment
22
3+ import android.app.Activity
4+ import android.content.Intent
35import android.net.Uri
46import android.os.Build
57import android.os.Bundle
8+ import android.os.Environment
9+ import android.provider.DocumentsContract
10+ import android.support.annotation.RequiresApi
611import android.support.design.widget.FloatingActionButton
712import android.support.v4.app.Fragment
813import android.text.Editable
@@ -64,6 +69,7 @@ import kotlinx.coroutines.Dispatchers
6469import kotlinx.coroutines.Job
6570import kotlinx.coroutines.launch
6671import kotlinx.coroutines.withContext
72+ import java.io.File
6773import java.security.MessageDigest
6874import kotlin.math.roundToInt
6975
@@ -96,6 +102,21 @@ class DecodeFragment : Fragment() {
96102 private var label: String? = null
97103 private var recreationSize = 0
98104
105+ override fun onActivityResult (
106+ requestCode : Int ,
107+ resultCode : Int ,
108+ resultData : Intent ?
109+ ) {
110+ when (requestCode) {
111+ OPEN_DOCUMENT -> {
112+ if (resultCode == Activity .RESULT_OK ) {
113+ val uri = resultData?.data ? : return
114+ activity?.openPickedFile(uri)
115+ }
116+ }
117+ }
118+ }
119+
99120 override fun onCreate (state : Bundle ? ) {
100121 super .onCreate(state)
101122 setHasOptionsMenu(true )
@@ -216,11 +237,11 @@ class DecodeFragment : Fragment() {
216237 ) = Unit
217238 })
218239 fab.setOnClickListener {
219- executeAction(this . content)
240+ executeAction(content)
220241 }
221242 if (justScanned && prefs.openImmediately) {
222243 closeAutomatically = true
223- executeAction(this . content)
244+ executeAction(content)
224245 }
225246 }
226247 }
@@ -575,22 +596,53 @@ class DecodeFragment : Fragment() {
575596 }
576597 }
577598
578- private fun executeAction (content : String ) {
599+ private fun executeAction (str : String ) {
579600 val ac = activity ? : return
580- if (content .isEmpty()) {
601+ if (str .isEmpty() || openLocalDocument(str )) {
581602 return
582603 }
583604 if (action is WifiAction &&
584605 Build .VERSION .SDK_INT < Build .VERSION_CODES .Q &&
585- ! ac.hasLocationPermission { executeAction(content ) }
606+ ! ac.hasLocationPermission { executeAction(str ) }
586607 ) {
587608 return
588609 }
589610 scope.launch {
590- action.execute(ac, content .toByteArray())
611+ action.execute(ac, str .toByteArray())
591612 }
592613 }
593614
615+ private fun openLocalDocument (str : String ): Boolean {
616+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .N ||
617+ ! str.startsWith(SCHEME_FILE )
618+ ) {
619+ return false
620+ }
621+ // Needs to be disabled so we get the result.
622+ closeAutomatically = false
623+ // file:// can't be used with Scoped Storage anymore.
624+ startActivityForResult(
625+ Intent (Intent .ACTION_OPEN_DOCUMENT ).apply {
626+ addCategory(Intent .CATEGORY_OPENABLE )
627+ type = " */*"
628+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
629+ val primary = str.substring(
630+ SCHEME_FILE .length
631+ ).localDirName() ? : Environment .getExternalStorageDirectory().path
632+ putExtra(
633+ DocumentsContract .EXTRA_INITIAL_URI ,
634+ DocumentsContract .buildDocumentUri(
635+ " com.android.externalstorage.documents" ,
636+ " primary:$primary "
637+ )
638+ )
639+ }
640+ },
641+ OPEN_DOCUMENT
642+ )
643+ return true
644+ }
645+
594646 private fun askForFileNameAndSave (raw : ByteArray ) {
595647 val ac = activity ? : return
596648 // Write permission is only required before Android Q.
@@ -617,6 +669,8 @@ class DecodeFragment : Fragment() {
617669
618670 companion object {
619671 private const val SCAN = " scan"
672+ private const val OPEN_DOCUMENT = 1
673+ private const val SCHEME_FILE = " file://"
620674
621675 fun newInstance (scan : Scan ): Fragment {
622676 val args = Bundle ()
@@ -810,3 +864,22 @@ private fun String.fold(): CharSequence {
810864 this
811865 }
812866}
867+
868+ private fun String.localDirName (): String? = when {
869+ endsWith(" /" ) -> this
870+ else -> File (this ).parentFile?.absolutePath
871+ }?.replaceFirst(Regex (" ^/storage/emulated/0/" ), " " )
872+ ?.replaceFirst(Regex (" ^/sdcard/" ), " " )
873+ ?.trim(' /' )
874+
875+ private fun Activity.openPickedFile (uri : Uri ) {
876+ startActivity(
877+ Intent .createChooser(
878+ Intent (Intent .ACTION_VIEW ).apply {
879+ setDataAndType(uri, contentResolver.getType(uri) ? : " */*" )
880+ addFlags(Intent .FLAG_GRANT_READ_URI_PERMISSION )
881+ },
882+ getString(R .string.open_url)
883+ )
884+ )
885+ }
0 commit comments