Proper way to handle playing mp3 in external storage - android

Trying to play an mp3 in the emulator's external storage (but not on an sd card). After some Googling I thought I had code that would work and also added the following lines to my app's AndroidManifest.xml file:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
It still fails and I found posts saying that apparently I need to request permission as well. Copied in some code I found that was supposed to do so but then I got a message from Android Studio saying that using it would limit what API level it would work with. Realized then I was way out of my depth on what is the right way to accomplish my goal. Some context for what API level is reasonable or sanity checking of my MediaPlayer code would be greatly appreciated. Thanks.
class MainActivity : AppCompatActivity()
{
private lateinit var mp: MediaPlayer
private var totalTime: Int = 0
override fun onCreate( savedInstanceState: Bundle? )
{
super.onCreate( savedInstanceState )
setContentView( R.layout.activity_main )
// this is the permission code I get the API level warning about
val MY_READ_EXTERNAL_REQUEST : Int = 1
if (checkSelfPermission(
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), MY_READ_EXTERNAL_REQUEST)
}
mp = MediaPlayer()
// path and name of mp3 file I'm trying to play
mp.setDataSource( "/storage/emulated/0/Music/Bad Guys Win.mp3" )
mp.prepare()
mp.start()
}
}
Permission Error:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.scratch/com.example.scratch.MainActivity}:
java.io.FileNotFoundException: /storage/emulated/0/Music/Bad Guys
Win.mp3: open failed: EACCES (Permission denied)
Screenshot of API warning from Android Studio

You are asking for permission, but you are not waiting for it to be granted. Use this callback method which is automatically called after a permission is granted:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(grantResults.size > 0 && grantResults.get(0) == PackageManager.PERMISSION_GRANTED){
// write your media player code here
}
}

Related

Unable to read internal storage in Android Kotlin

I come to you in a time of great need. I am currently learning to use Kotlin for app development and as a "project" per-say, I am working on a simple "File manager". The current problem I am experiencing is that I am unable to read the directories and the files.
Using API 26
Using Kotlin
Using ViewModel
The permissions in the AndroidManifest.xml are set
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
The permission request in runtime is called in MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (checkPermission()) {
//permission allowed
val path = Environment.getExternalStorageDirectory().path
val filesAndFolders: Array<File>? = File(path).listFiles()
Log.d("FILETAG", path) // /storage/emulated/0
Log.d("FILETAG", filesAndFolders.toString()) // null
Log.d("FILETAG", File(path).exists().toString()) // true
Log.d("FILETAG", File(path).canRead().toString()) // false
} else {
//permission not allowed
requestPermission()
}
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
}
private fun checkPermission(): Boolean {
val result =
ContextCompat.checkSelfPermission(
this,
android.Manifest.permission.READ_EXTERNAL_STORAGE
)
return result == PackageManager.PERMISSION_GRANTED
}
private fun requestPermission(){
if(ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)){
Toast.makeText(this, "Storage permission is required", Toast.LENGTH_SHORT).show()
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
111
)
}
}
As commented in the code, the file array is returned as a "null", though the files seem to exist but are unreadable.
Additionally, I have tried executing this code from an inside of the fragment, but with the exact same results, though am required to read the files in a fragment rather than inside the MainActivity (But I first need to get this part of my code working before I move on to the fragments) and list the files in a RecyclerView.
This is my first question on Stackoverflow, if I missed any essential detail, let me know.
Please grant me your infinite knowledge, thank you.

Android: Check if Permisson is granted in another Class, not in the MainActivity

I am new to Android App development and I'd really like to know if there is a way to check in another Class (a Foreground Service that gathers some location data) if the location Permission was given in the Main Activity.
In my main Activity, I am requesting the permission straight upon app start like this:
private fun requestPermissions() {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_ID
)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_ID) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
Toast.makeText(this, "Right Permissions Granted", Toast.LENGTH_LONG).show()
}
}
}
}
Its working and I can give my app the permission to access the location. To use a function in my other I class, I need to check if the permission was granted, and I do it like this:
fun dummy(){
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
// do work that needs the location permission
}
}
However, if I try to execute this function, I get a null pointer reference. What am I missing here?
Thank you!
You can't request permissions from a Service. The reason is that when the request permission dialog comes up, the user is naturally going to think it belongs to the foreground app. THat confusion is why Google doesn't allow it. My best suggestion would be to launch an Activity that then asks for permission.

I am making a gallery like UI for my app, what permissions do i need to ask for if I am targetting Android 11?

I am using MediaStore to recieve the ids of all the images stored on the device using
private fun getImageUris(): List<Uri> {
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media._ID)
val mCursor = requireActivity().contentResolver.query(
uri,
projection,
null,
null,
null
)
val imageUris = mutableListOf<Uri>()
while (mCursor?.moveToNext() == true) {
val columnIndex = mCursor.getColumnIndex(MediaStore.Images.Media._ID)
val imageId = mCursor.getInt(columnIndex)
val currentImageUri = Uri.withAppendedPath(uri, imageId.toString())
imageUris.add(currentImageUri)
}
mCursor?.close()
return imageUris
}
and then i ask for the permission in onViewCreated() of my fragment like this:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding = FragmentMainBinding.bind(view)
when {
isStoragePermissionGranted -> {
binding.recyclerView.adapter = RecyclerViewAdapter(getImageUris())
}
shouldShowRequestPermissionRationale -> {
Toast.makeText(mainActivity, "Please grant storage permission", Toast.LENGTH_SHORT).show()
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), STORAGE_PERMISSION_REQUEST_CODE)
}
else -> {
Toast.makeText(mainActivity, "Permission not granted. Images cannot be shown.", Toast.LENGTH_SHORT).show()
}
}
}
I expect this to ask for the storage permission as soon as the app is opened (and my fragment is created) and then it should load all the images on the phone in my recycler view (I am using glide). But it doesn't work the way its expected to, instead the
"Permission not granted. Images cannot be shown."
toast message is shown
For a quick workaround, you can add this in the manifest file under <application>
android:requestLegacyExternalStorage="true"
Read about the storage update for Android 11 here
The problem was here as noted by #blackapps
shouldShowRequestPermissionRationale -> {
Toast.makeText(mainActivity, "Please grant storage permission", Toast.LENGTH_SHORT).show()
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), STORAGE_PERMISSION_REQUEST_CODE)
because shouldShowRequestPermissionRationale is only true when the "deny and don't ask again" option is showing with the permission pop up and that option only appears after the first time the permission has been asked for (which never happens since in order for that to happen, shouldShowRequestPermissionRationale needs to be true).
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
use above permission and in application write below code:
<application
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"/

Android - Permission Dialog not showing on button click

In my application, i need to request write and read permission from the storage. Since i want to show the user that the app needs these permissions, i have created and Activity containing a button, which on click, should call the Storage permission Dialog.
However, since the recent Android changes, this doesnt work anymore.
Is there a new (and clean) way to ask permission? Am i doing something wrong?
I have added the uses-permission line inside the AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
This is the code inside the Activity:
class ActivityPermission : AppCompatActivity() {
companion object {
var PERMISSION_REQUEST_CODE = 12
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPermissionBinding.inflate(layoutInflater)
setContentView(R.layout.activity_permission)
binding.btnPermission.setOnClickListener {
ActivityCompat.requestPermissions(this, arrayOf(
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE),
PERMISSION_REQUEST_CODE)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == PERMISSION_REQUEST_CODE) {
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, getString(R.string.permissiongranted), Toast.LENGTH_SHORT).show();
finish()
} else {
Toast.makeText(this, getString(R.string.permissiondenied), Toast.LENGTH_SHORT).show();
}
}
}
}
Thanks to everyone for helping me discover more about Android Permissions.
I decided to change the way i ask for the permission. Instead of an Activity, i decided to use a Fragment instead ("show an educational UI to the user. In this UI, describe why the feature, which the user wants to enable, needs a particular permission." - source | Thanks to #Michael in the comments for pointing it out).
Since now im using a Fragment, i have to use requestPermissions (Thanks to this reply). This now works flawlessly without any issues.
Turns out you need a combination of checks when trying to request a permission. You have to first check if the permission is actually enabled with checkSelfPermission, so you can easily choose where the user should go to start using the app.

FileError {code: 6, message: “NO_MODIFICATION_ALLOWED_ERR”}

I am trying to remove a file from the local storage of my phone device.
I have given the path and filename and both exist.
I ran file.checkDir & file.checkFile to confirm whether its getting the path and it returned true.
I tried it on multiple android devices and observed that its only getting deleted for android versions below 8. I am not aware of any plugin update for the higher android version if there is any. I tried to google it but there is nowhere mentioned regarding plugin update.
Its throwing this error:
FileError {code: 6, message: “NO_MODIFICATION_ALLOWED_ERR”}
Although I have mentioned the permissions:
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.READ_EXTERNAL_STORAGE
I am not sure about what I am doing wrong here.
Thanks for the help.
this.file.removeFile(path, fileName)
Expected - File should be removed from the given path
Actual - File not being removed from the given path
From sdk21, if Im not mistaken, not enough to specify permission in manifets. You have to request it in runtime and check that you have it any time, when you are going to use it. Smth like that
const val INTERET = Manifest.permission.INTERNET
const val READ = Manifest.permission.READ_EXTERNAL_STORAGE
const val WRITE = Manifest.permission.WRITE_EXTERNAL_STORAGE
const val LOCATION_COARSE = Manifest.permission.ACCESS_COARSE_LOCATION
const val LOCATION_FINE = Manifest.permission.ACCESS_FINE_LOCATION
const val PHONE = Manifest.permission.CALL_PHONE
fun granted(activity: Activity, vararg permission: String): Boolean {
val list = ArrayList<String>()
for (s in permission)
if (ActivityCompat.checkSelfPermission(activity, s) != PackageManager.PERMISSION_GRANTED)
list.add(s)
if (list.isEmpty())
return true
ActivityCompat.requestPermissions(activity, list.toArray(arrayOfNulls<String>(list.size)), 1)
return false
}
and in code check permission:
if(granted(this, READ, WHRITE)
this.file.removeFile(path, fileName)
else
//do smth if you have no permission
good for you to react if user denied permission. You can do it in Activity.onRequestPermissionsResult

Categories

Resources