WriteExternalDelegate.kt 4.78 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
package org.videolan.vlc.gui.helpers.hf

import android.annotation.TargetApi
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.DocumentsContract
import android.support.v4.app.FragmentActivity
import android.support.v4.provider.DocumentFile
12
import android.support.v7.app.AlertDialog
13 14 15
import android.support.v7.preference.PreferenceManager
import android.text.TextUtils
import org.videolan.libvlc.util.AndroidUtil
16
import org.videolan.vlc.R
17 18 19 20 21 22 23 24 25 26
import org.videolan.vlc.VLCApplication
import org.videolan.vlc.util.AndroidDevices
import org.videolan.vlc.util.FileUtils


class WriteExternalDelegate : BaseHeadlessFragment() {

    @TargetApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
27 28 29 30 31
        showDialog()
    }

    private fun showDialog() {
        if (!isAdded) return
32
        val builder = AlertDialog.Builder(activity!!)
33 34 35 36 37 38 39 40 41 42 43 44 45 46
        builder.setMessage(R.string.sdcard_permission_dialog_message)
                .setTitle(R.string.sdcard_permission_dialog_title)
                .setPositiveButton(R.string.ok, { _, _ ->
                    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
                    arguments?.getString(KEY_STORAGE_PATH)?.let { intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse(it)) }
                    startActivityForResult(intent, REQUEST_CODE_STORAGE_ACCES)
                })
                .setNeutralButton(getString(R.string.dialog_sd_wizard), { _, _ ->
                    showHelpDialog()
                }).create().show()
    }

    private fun showHelpDialog() {
        if (!isAdded) return
47 48 49 50 51 52
        activity?.let {
            val inflater = it.layoutInflater
            AlertDialog.Builder(it).setView(inflater.inflate(R.layout.dialog_sd_write, null))
                    .setOnDismissListener { showDialog() }
                    .create().show()
        }
53 54 55 56 57 58
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (data !== null && requestCode == REQUEST_CODE_STORAGE_ACCES) {
            if (resultCode == Activity.RESULT_OK) {
59
                val context = context ?: return
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
                val treeUri = data.data
                PreferenceManager.getDefaultSharedPreferences(VLCApplication.getAppContext()).edit()
                        .putString("tree_uri_"+ storage, treeUri.toString()).apply()
                val treeFile = DocumentFile.fromTreeUri(context, treeUri)
                val contentResolver = context.contentResolver

                // revoke access if a permission already exists
                val persistedUriPermissions = contentResolver.persistedUriPermissions
                for (uriPermission in persistedUriPermissions) {
                    val file = DocumentFile.fromTreeUri(context, uriPermission.uri)
                    if (treeFile.name == file.name) {
                        contentResolver.releasePersistableUriPermission(uriPermission.uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                        return
                    }
                }

                // else set permission
                contentResolver.takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                permissions = contentResolver.persistedUriPermissions
                executeCallback()
                return
            }
        }
        callback = null
    }

    companion object {
        internal const val TAG = "VLC/WriteExternal"
        internal const val KEY_STORAGE_PATH = "VLC/storage_path"
        private const val REQUEST_CODE_STORAGE_ACCES = 42
        private var permissions = VLCApplication.getAppContext().contentResolver.persistedUriPermissions
        private lateinit var storage: String

        fun askForExtWrite(activity: FragmentActivity?, uri: Uri, cb: Runnable? = null) {
            if (activity === null) return
            val fragment = WriteExternalDelegate()
            callback = cb
97
            storage = FileUtils.getMediaStorage(uri) ?: return
98 99 100 101 102 103 104 105 106 107 108 109 110
            fragment.arguments = Bundle(1).apply { putString(KEY_STORAGE_PATH, storage) }
            activity.supportFragmentManager.beginTransaction().add(fragment, TAG).commitAllowingStateLoss()
        }

        fun needsWritePermission(uri: Uri) : Boolean {
            val path = uri.path
            return AndroidUtil.isLolliPopOrLater && "file" == uri.scheme
                    && !TextUtils.isEmpty(path) && path.startsWith('/')
                    && !path.startsWith(AndroidDevices.EXTERNAL_PUBLIC_DIRECTORY)
                    && !(FileUtils.findFile(uri)?.canWrite() ?: false)
        }
    }
}