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
Related
Migrating from android 30 to the android 31 version, I am trying to connect to the paired Bluetooth device in my app.
But, I am facing an issue when I tried to get the paired device list.
val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
if(device.address.lowercase() == configHelper.bluetoothAddress.lowercase()){
bluetoothDevice = device
paymentTerminalName = device.name
paymentTerminalMAC = device.address // MAC address
UUIDFromPaymentTerminal = device.uuids[0].uuid // UUID specifies the service that the the server provides
}
}
if(bluetoothDevice == null){
//payment terminal is not paired yet
throw ex
}
socket = bluetoothDevice!!.createRfcommSocketToServiceRecord(UUIDFromPaymentTerminal)
//cancel discovery, otherwise it slows down the connection process
bluetoothAdapter!!.cancelDiscovery()
(socket!! as BluetoothSocket).connect()
I am getting the below error,
java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT
permission for AttributionSource { uid = 10414, packageName =
com.test.app, attributionTag = null, token =
android.os.BinderProxy#8a4f87d, next = null }: AdapterService
getBondedDevices
I have added bluetooth permission to my manifest file,
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
Let me know where am I missing to get the paired device in kotlin 1.5.0
The BLUETOOTH_CONNECT & BLUETOOTH_SCAN permissions are runtime permissions, these permissions have to be asked during the runtime of your application.
The BLUETOOTH_SCAN permission should be asked before you scan for devices and the BLUETOOTH_CONNECT permission should be asked before you connect to a device.
An example of a permission requester for an single permission within the Fragments architecture:
val requestConnectPermission: ActivityResultLauncher<String> =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { permissionGranted ->
if (permissionGranted) {
// connect to device
}
}
An example of a requester for multiple permissions within the Fragments architecture:
val permissionRequester: ActivityResultLauncher<Array<String>> = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions.values.all { it }) {
// connect to device
}
}
To handle a single permission request within an Composable is slightly different, you can do the following:
val permissionRequester =
rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
// connect to device
}
}
requestConnectPermission?.launch(Manifest.permission.BLUETOOTH_CONNECT)
And for multiple permissions at once:
val permissionRequester =
rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions.values.all { it }) {
// connect to device
}
}
Before you should use such a permission launcher you should check if the user has already accepted the permissions. If not you can launch a request. An example to launch a single permission request:
if (ActivityCompat.checkSelfPermission(requireContext(), BLUETOOTH_CONNECT) == PERMISSION_GRANTED) {
// connect to device
} else {
permissionRequester.launch(BLUETOOTH_CONNECT)
}
And if you want to launch multiple permission requests at once you can do this:
if (ActivityCompat.checkSelfPermission(requireContext(), BLUETOOTH_CONNECT) == PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(requireContext(), BLUETOOTH_SCAN) == PERMISSION_GRANTED) {
// connect to device
} else {
permissionRequester.launch(arrayOf(BLUETOOTH_CONNECT, BLUETOOTH_SCAN))
}
More info about permissions can be found here.
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.
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"/
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
}
}
I am creating a library that needs to check runtime permissions. I have got runtime permissions working fine and understand the use cases without issues.
However I would like to confirm that the developer using our library has added the permission to their manifest.
The library is a location based library and the developer can either enter ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION into the manifest and I need to be able to determine which they have used (or both) at runtime.
I though using the package manager to check permission would work however this always seems to fail:
PackageManager pm = getPackageManager();
int granted = pm.checkPermission(
Manifest.permission.ACCESS_COARSE_LOCATION,
getPackageName() );
if (granted == PackageManager.PERMISSION_GRANTED)
{
// Use coarse for runtime requests
}
// granted is always PackageManager.PERMISSION_DENIED
Is there some other way to do this in Android v23+?
Off the cuff, retrieve the PackageInfo via PackageManager and getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS). Then, look at the requestedPermissions array in the PackageInfo for all the <uses-permission>-requested permissions.
Thanks to answer of CommonsWare I'm created this method Kotlin to check if SMS permission is present on Manifest
fun hasSmsPermissionInManifest(context: Context): Boolean {
val packageInfo = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
val permissions = packageInfo.requestedPermissions
if (permissions.isNullOrEmpty())
return false
for (perm in permissions) {
if (perm == Manifest.permission.READ_SMS || perm == Manifest.permission.RECEIVE_SMS)
return true
}
return false
}
or
fun Context.hasSmsPermissionInManifest(): Boolean {
val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
val permissions = packageInfo.requestedPermissions
return permissions?.any { perm -> perm == Manifest.permission.READ_SMS || perm == Manifest.permission.RECEIVE_SMS } ?: false
}