Android read text file with request permission at runtime

Android example to read text file, with request permission at runtime.

To read file in Android, if your app is installed on device that runs Android 6.0 (API level 23) or higher, you must request the dangerous permissions at runtime. (ref: Android Developers : Request app permissions)

Also shown in the video, access to /proc/net filesystem is restricted on Android 10+

On devices that run Android 10 or higher, apps cannot access /proc/net, which includes information about a device's network state. Apps that need access to this information, such as VPNs, should use the NetworkStatsManager or ConnectivityManager class. (ref: Android Developers: Privacy changes in Android 10 > Restriction on access to /proc/net filesystem)

layout xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">

<LinearLayout
android:id="@+id/leftpanel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/black"
android:layout_margin="5dp"
android:padding="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="@color/white"
android:text="android-er.blogspot.com"/>
<TextView
android:id="@+id/exercise"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textColor="@color/white"
android:text="Exercise: Read Text File"/>
<TextView
android:id="@+id/sysinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="@color/white"/>
<TextView
android:id="@+id/sdkinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="@color/white"/>

</LinearLayout>

<RelativeLayout
android:id="@+id/rightpanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#C0C0C0"
android:layout_margin="5dp"
android:padding="5dp">
<Button
android:id="@+id/read"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:text="Read"
android:layout_alignParentTop="true"/>
<TextView
android:id="@+id/filecontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:background="#808080"
android:fontFamily="monospace"
android:layout_below="@id/read"
android:layout_above="@id/msg"/>
<TextView
android:id="@+id/msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:background="#404040"
android:layout_gravity="bottom"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
</LinearLayout>
Java code:
package android_er.blogspot.com.jexreadtextfile;

import android.Manifest;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

//Try different files
//String targetFile = "/sdcard/Download/Test.txt";
//String targetFile = "/proc/cpuinfo";
//String targetFile = "/proc/meminfo";
String targetFile = "/proc/net/arp"; //Restricted since Android 10

Button btnRead;
TextView tvFileContent;
TextView tvMsg;

final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dispExInfo();

btnRead = findViewById(R.id.read);
btnRead.setText(targetFile);
tvFileContent = findViewById(R.id.filecontent);
//make this TextView scrollable
tvFileContent.setMovementMethod(new ScrollingMovementMethod());
tvMsg = findViewById(R.id.msg);
tvMsg.setText("Click on READ button");

btnRead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tvMsg.setText("READ button clicked");
toReadFile();
}
});
}


/*
Request Permission at Runtime, before read file.
*/
void toReadFile(){
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.

//to simplify, call requestPermissions again
Toast.makeText(getApplicationContext(),
"shouldShowRequestPermissionRationale",
Toast.LENGTH_LONG).show();
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
} else {
// No explanation needed; request the permission
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
}
}else{
// permission granted
readFile(targetFile);
}
}

@Override
public void onRequestPermissionsResult(
int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
if(requestCode == PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE){
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted.
Toast.makeText(getApplicationContext(),
"permission was granted, thx:)",
Toast.LENGTH_LONG).show();

readFile(targetFile);
} else {
// permission denied.
Toast.makeText(getApplicationContext(),
"permission denied! Oh:(",
Toast.LENGTH_LONG).show();
}
return;

}else{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}

void readFile(String f){
File file = new File(f);
StringBuilder stringBuilder = new StringBuilder();

try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line);
stringBuilder.append('\n');
}
bufferedReader.close();

tvFileContent.setText(stringBuilder);
tvMsg.setText("Done");
} catch (FileNotFoundException e) {
e.printStackTrace();
tvMsg.setText(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
tvMsg.setText(e.getMessage());
}
}

/* ==========================================
display Exercise info
*/

void dispExInfo(){
TextView tvExercise = findViewById(R.id.exercise);
TextView tvSysInfo = findViewById(R.id.sysinfo);
TextView tvSdkInfo = findViewById(R.id.sdkinfo);

tvExercise.append(" (Java)");

String manufacturer = Build.MANUFACTURER;
String model = Build.MODEL;
String release = Build.VERSION.RELEASE;

tvSysInfo.setText(
manufacturer + "\n"
+ model + "\n"
+ "Android: " + release + "\n");

PackageManager packageManager = getPackageManager();
String packageName = getPackageName();
int targetSdkVersion, minSdkVersion;
int versionCode;
String versionName;

try {
PackageInfo packageInfo =
packageManager.getPackageInfo(packageName, 0);

ApplicationInfo applicationInfo = packageInfo.applicationInfo;
targetSdkVersion = applicationInfo.targetSdkVersion;
minSdkVersion = applicationInfo.minSdkVersion;

tvSdkInfo.setText("targetSdkVersion = " + targetSdkVersion + "\n"
+ "minSdkVersion = " + minSdkVersion);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"NameNotFoundException: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}

uses-permission of "android.permission.READ_EXTERNAL_STORAGE" is needed in AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android_er.blogspot.com.jexreadtextfile">
<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.JExReadTextFile">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

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


Kotlin version, basically auto-converted by Android Studio.
package android_er.blogspot.com.kexreadtextfile

import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.io.*


class MainActivity : AppCompatActivity() {
//Try different files
//var targetFile = "/sdcard/Download/Test.txt";
var targetFile = "/proc/cpuinfo";
//var targetFile = "/proc/meminfo";
//var targetFile = "/proc/net/arp" //Restricted since Android 10
var btnRead: Button? = null
var tvFileContent: TextView? = null
var tvMsg: TextView? = null
val PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
dispExInfo()
btnRead = findViewById(R.id.read)
btnRead!!.setText(targetFile)
tvFileContent = findViewById(R.id.filecontent)
//make this TextView scrollable
tvFileContent!!.setMovementMethod(ScrollingMovementMethod())
tvMsg = findViewById(R.id.msg)
tvMsg!!.setText("Click on READ button")
btnRead!!.setOnClickListener(View.OnClickListener {
tvMsg!!.setText("READ button clicked")
toReadFile()
})
}

/*
Request Permission at Runtime, before read file.
*/
fun toReadFile() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.

//to simplify, call requestPermissions again
Toast.makeText(applicationContext,
"shouldShowRequestPermissionRationale",
Toast.LENGTH_LONG).show()
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE)
} else {
// No explanation needed; request the permission
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE)
}
} else {
// permission granted
readFile(targetFile)
}
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray) {
if (requestCode == PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE) {
if (grantResults.size > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted.
Toast.makeText(applicationContext,
"permission was granted, thx:)",
Toast.LENGTH_LONG).show()
readFile(targetFile)
} else {
// permission denied.
Toast.makeText(applicationContext,
"permission denied! Oh:(",
Toast.LENGTH_LONG).show()
}
return
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}

fun readFile(f: String?) {
val file = File(f)
val stringBuilder = StringBuilder()
try {
val bufferedReader = BufferedReader(FileReader(file))
var line: String?
while (bufferedReader.readLine().also { line = it } != null) {
stringBuilder.append(line)
stringBuilder.append('\n')
}
bufferedReader.close()
tvFileContent!!.text = stringBuilder
tvMsg!!.text = "Done"
} catch (e: FileNotFoundException) {
e.printStackTrace()
tvMsg!!.text = e.message
} catch (e: IOException) {
e.printStackTrace()
tvMsg!!.text = e.message
}
}

/* ==========================================
display Exercise info
*/
fun dispExInfo() {
val tvExercise = findViewById<TextView>(R.id.exercise)
val tvSysInfo = findViewById<TextView>(R.id.sysinfo)
val tvSdkInfo = findViewById<TextView>(R.id.sdkinfo)
tvExercise.append(" (Kotlin)")
val manufacturer = Build.MANUFACTURER
val model = Build.MODEL
val release = Build.VERSION.RELEASE
tvSysInfo.text = """
$manufacturer
$model
Android: $release

""".trimIndent()
val packageManager = packageManager
val packageName = packageName
val targetSdkVersion: Int
val minSdkVersion: Int
var versionCode: Int
var versionName: String
try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
val applicationInfo = packageInfo.applicationInfo
targetSdkVersion = applicationInfo.targetSdkVersion
minSdkVersion = applicationInfo.minSdkVersion
tvSdkInfo.text = """
targetSdkVersion = $targetSdkVersion
minSdkVersion = $minSdkVersion
""".trimIndent()
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
Toast.makeText(applicationContext,
"NameNotFoundException: " + e.message,
Toast.LENGTH_LONG).show()
}
}
}

Post a Comment

Previous Post Next Post