1

I'm attempting to read a plain text file in external storage, but I'm getting an exception related to permissions. The goal is to read a plain text file from the Download folder in the sdcard and show the contents in a TextView. I'm getting a permissions related error. This is what I've got so far:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.externalstoragesample">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ExternalStorageSample">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MainActivity.kt:

package com.example.android.externalstoragesample

import android.Manifest
import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import java.io.File
import androidx.core.app.ActivityCompat
import android.content.pm.PackageManager

private const val TAG = "LogTag"
private const val OPEN_DOCUMENT_REQUEST_CODE = 3

// Storage Permissions
private const val REQUEST_EXTERNAL_STORAGE = 1
private val PERMISSIONS_STORAGE = arrayOf(
    Manifest.permission.READ_EXTERNAL_STORAGE
)

class MainActivity : AppCompatActivity() {

    private lateinit var importButton : Button
    private lateinit var outputText : TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        importButton = findViewById(R.id.importButton)
        outputText = findViewById(R.id.outputText)

        importButton.setOnClickListener {
            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
                type = "text/plain"
                addCategory(Intent.CATEGORY_OPENABLE)
            }
            Log.v(TAG, "Calling startActivityForResult...")
            startActivityForResult(intent, OPEN_DOCUMENT_REQUEST_CODE)
            Log.v(TAG, "startActivityForResult has been called")
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == OPEN_DOCUMENT_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                Log.v(TAG, "Let's check what we have")
                data?.data?.also { documentUri ->
                    val path = documentUri.path
                    Log.v(TAG, "Document URI is $documentUri with path $path")
                    Log.v(TAG, "Verifying storage permissions...")
                    verifyStoragePermissions()
                    Log.v(TAG, "Creating File object...")
                    val file = File(path!!.substring(documentUri.path!!.indexOf(':') + 1))
                    Log.v(TAG, "Reading file...")
                    val fileContent = file.readLines()
                    var readContent = ""
                    for (line in fileContent) {
                        readContent +=  line + "\n"
                    }
                    Log.v(TAG, "Read content: $readContent")
                    outputText.text = readContent
                }
            } else {
                Log.v(TAG, "onActivityResult resultCode is not OK=$resultCode")
            }
        } else {
            Log.v(TAG, "onActivityResult unknown requestCode=$requestCode")
        }
    }

    private fun verifyStoragePermissions() {
        // Check if we have read permission
        val permission = ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.READ_EXTERNAL_STORAGE
        )
        if (permission != PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG, "We don't have permission so prompt the user")
            ActivityCompat.requestPermissions(
                this,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
            )
        } else {
            Log.v(TAG, "We have permission")
        }
    }
}

When I open the app, I press the button and the file picker pops up. As soon as I choose the file hello.txt the app crashes. This is what I see as the output in Android Studio:

V/LogTag: Calling startActivityForResult...
V/LogTag: startActivityForResult has been called
D/EGL_emulation: eglMakeCurrent: 0xdf6be6c0: ver 3 0 (tinfo 0xd40ae700)
V/LogTag: Let's check what we have
V/LogTag: Document URI is content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fhello.txt with path /document/raw:/storage/emulated/0/Download/hello.txt
    Verifying storage permissions...
V/LogTag: We have permission
    Creating File object...
V/LogTag: Reading file...
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.android.externalstoragesample, PID: 9541
    java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=3, result=-1, data=Intent { dat=content://com.android.providers.downloads.documents/document/raw:/storage/emulated/0/Download/hello.txt flg=0x43 }} to activity {com.example.android.externalstoragesample/com.example.android.externalstoragesample.MainActivity}: java.io.FileNotFoundException: /storage/emulated/0/Download/hello.txt: open failed: EACCES (Permission denied)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4845)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4886)
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.io.FileNotFoundException: /storage/emulated/0/Download/hello.txt: open failed: EACCES (Permission denied)
        at libcore.io.IoBridge.open(IoBridge.java:496)
        at java.io.FileInputStream.<init>(FileInputStream.java:159)
        at kotlin.io.FilesKt__FileReadWriteKt.forEachLine(FileReadWrite.kt:190)
        at kotlin.io.FilesKt__FileReadWriteKt.readLines(FileReadWrite.kt:219)
        at kotlin.io.FilesKt__FileReadWriteKt.readLines$default(FileReadWrite.kt:217)
        at com.example.android.externalstoragesample.MainActivity.onActivityResult(MainActivity.kt:65)
        at android.app.Activity.dispatchActivityResult(Activity.java:8110)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4838)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4886) 
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
     Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
        at libcore.io.Linux.open(Native Method)
        at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
        at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
        at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
        at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7255)
        at libcore.io.IoBridge.open(IoBridge.java:482)
        at java.io.FileInputStream.<init>(FileInputStream.java:159) 
        at kotlin.io.FilesKt__FileReadWriteKt.forEachLine(FileReadWrite.kt:190) 
        at kotlin.io.FilesKt__FileReadWriteKt.readLines(FileReadWrite.kt:219) 
        at kotlin.io.FilesKt__FileReadWriteKt.readLines$default(FileReadWrite.kt:217) 
        at com.example.android.externalstoragesample.MainActivity.onActivityResult(MainActivity.kt:65) 
        at android.app.Activity.dispatchActivityResult(Activity.java:8110) 
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4838) 
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4886) 
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
I/Process: Sending signal. PID: 9541 SIG: 9

ArthurTheLearner
  • 315
  • 4
  • 12
  • You are trying to convert a nice uri to a path. Dont do such things. Use the uri to open an input stream for it. Then read lines from the stream. – blackapps Oct 12 '21 at 17:07

0 Answers0