Android Question B4A 12.80 and Android 14

Pedro Caldeira

Active Member
Licensed User
Longtime User
My Apps show the Error "This App is not compatible with the latest Android version. ....", when. of course, installed in an Android 14 device.
I Get this error in the log window:

Error Android 14:
ERROR>> Error: java.lang.SecurityException: Caller xevolution.vrcg.v2900.simacail needs to hold android.permission.SCHEDULE_EXACT_ALARM or android.permission.USE_EXACT_ALARM to set exact alarms.
ERROR>> StackTrace: java.lang.SecurityException: Caller xevolution.vrcg.v2900.simacail needs to hold android.permission.SCHEDULE_EXACT_ALARM or android.permission.USE_EXACT_ALARM to set exact alarms.

But I have in the manifest the following lines

AddPermission(android.SCHEDULE_EXACT_ALARM)
AddPermission(android.USE_EXACT_ALARM)


What can I do to solve this?
 

BlueVision

Active Member
Licensed User
Longtime User
Had to deal with that too.
The following is not prooved, only an idea what happened:

Google implemented a mechanism in Android 14, that prevents running of an app with a fairly "outdated" SDK-Level. I had to change the TARGET-SDK-Level from 29 to the now recommended level (think it is 33 now, there should be a message within the IDE). Then it started without that message on Android 14.

The problem with my app: It runs without this message on SDK33 but is useless from now on, because there is no longer access to the download-folder. The download-folder was the place for interchanging downloaded stuff, the app works with. I see no workaround for this, there will be no further development of this app for Android.

It is like it is, the automatic pick-up from that place of communication interchange is no longer an option because of security. Most users never had a problem with that, but have a problem with newly established delivery methods of the downloaded file (defining a save folder and so on.) So it would be a waste of time for me to continue my project. Sad as it is. Thank you Google. If this is not a problem with your application, you are lucky.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
But I have in the manifest the following lines

AddPermission(android.SCHEDULE_EXACT_ALARM)
AddPermission(android.USE_EXACT_ALARM)


What can I do to solve this?
Using
B4X:
AddPermission("android.permission.SCHEDULE_EXACT_ALARM")
? And even request for Permission before using it with runtimepermissions.
 
Upvote 0

Pedro Caldeira

Active Member
Licensed User
Longtime User
I have the SDK Target Version set to 33, and have placed only the reference as AddPermission("android.permission.SCHEDULE_EXACT_ALARM"), but I still get that message. I get tat error and later another error, while attempting to open my DB that resides in the sharedfolder.

java.lang.RuntimeException: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /storage/emulated/0/Android/data/xevolution.vrcg.v2900.simacail/files/orion/evolutioncheck.db3

Have to dig a bit deeper it seems
 
Upvote 0

BlueVision

Active Member
Licensed User
Longtime User
Starting in Android 11, third-party apps — even those that hold the MANAGE_EXTERNAL_STORAGE permission AKA "all files access" — are no longer allowed to access files and folders under /Android/data or /Android/obb. Android 11+ also blocks apps from gaining access to these folders using the Storage Access Framework (SAF).

Are you able to access the destination?
 
Upvote 0

BlueVision

Active Member
Licensed User
Longtime User
By download folder you mean the shared folder ?
No. It's simply the folder "Download(s)", located in the root. No longer accessible (I think starting SDK30).

The shared folder you are probably using is the folder /Android/data/name of your application/...

have a look here, frustrated programmers

Worth trying to limit your app to Android 13 and try then. But I think if Android 15 or 16 comes out, you run into the same problems.
Open the database from within the assets is no option. It does not work and you only have read-access granted.

Maybe defining a save folder could be an option and copying it from the assets to that location and work with the file there...
Never tried that, switched from B4A to B4J because of that politics made by Google.
As I understand it, you have to ask the user for a safe location for granting the access rights. This does not override the blocked access to the general download folder or the data-folder of your app. In my opinion, most of the users are simply overwhelmed with that principle and irritated.

But let's see what others say, I am not an expert...
 
Last edited:
Upvote 0

Pedro Caldeira

Active Member
Licensed User
Longtime User
No. It's simply the folder "Download(s)", located in the root. No longer accessible (I think starting SDK30).

The shared folder you are probably using is the folder /Android/data/name of your application/...

have a look here, frustrated programmers

Worth trying to limit your app to Android 13 and try then. But I think if Android 15 or 16 comes out, you run into the same problems.
Open the database from within the assets is no option. It does not work and you only have read-access granted.

Maybe defining a save folder could be an option and copying it from the assets to that location and work with the file there...
Never tried that, switched from B4A to B4J because of that politics made by Google.
I already copy the BD from the assets to the shared folder, and browsing the device the BD is written in the later folder, so I still have access. That means the I am experiencing another problem.
 
Upvote 0

BlueVision

Active Member
Licensed User
Longtime User
You followed DonManfred's advice with asking for a runtimepermission? This has to be included also within the program's code, not (only) in manifest.

Defining...:
Public RP As RuntimePermissions

Only a small example how to implement a runtimepermission:
    RP.CheckAndRequest(RP.PERMISSION_READ_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result Then
        If File.Exists(SharedFolder,"Config.dta")=True Then
            Dim Count As Int
            Dim Readout As String
            Readout = File.ReadString(SharedFolder,"Config.dta")
            For i = 0 To Readout.Length-1
                If Readout.CharAt(i) = ";" Then
                    Count = Count+1
                End If
            Next
            Log ("Count="&Count)
                Log (Readout)
'                File.WriteString(SharedFolder,"Config.dta",Readout&";0")
'                Sleep(0)
'                RestorePersonal
'                BSave_Click
        End If
    End If
 
Upvote 0

Pedro Caldeira

Active Member
Licensed User
Longtime User
I use that method for several other RP, but I was checkling, and the lib runtimepermissions, doesn't expose that permission yet.
 
Last edited:
Upvote 0

BlueVision

Active Member
Licensed User
Longtime User
I see...
As I understand, you should try using:
USE_EXACT_ALARM
(Yes it is denied by default, but if requested in manifest it should be granted by the system. My understanding, can't try it, have no Android 14 device).
In opposite to
SCHEDULE_EXACT_ALARM, this has to be granted by the user.
Eventually you have to uninstall the app and install again from scratch (this is clearing the granted rights).
Hard to see what happens without knowing the code. It's only clear, that a needed permission is not granted.
Are you able to explain why you need a scheduling? I see no need for it for accessing a database. Depends on what you want to do.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
you can refer to particular runtime permissions in b4a by their full string name if the constant is not available.
 
Last edited:
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
Simply requesting the runtime permission won't work if you're targeting Android 13+. You need to take the user to the "Alarms & reminders" section in the device settings (Settings->Apps->Special app access->Alarms & reminders) & ask them to turn the "Allow setting alarms & reminders" setting on. Otherwise you can only use inexact alarms.

You might want to look at this -> https://developer.android.com/about/versions/14/changes/schedule-exact-alarms

- Colin.
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
I have the SDK Target Version set to 33, and have placed only the reference as AddPermission("android.permission.SCHEDULE_EXACT_ALARM"), but I still get that message. I get tat error and later another error, while attempting to open my DB that resides in the sharedfolder.

java.lang.RuntimeException: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /storage/emulated/0/Android/data/xevolution.vrcg.v2900.simacail/files/orion/evolutioncheck.db3

Have to dig a bit deeper it seems
You're asking 2 different questions in one thread. You might want to start another thread for the 2nd question...

Maybe post the code around where you're getting this error, but my guess is that you've closed the database somewhere & now you're trying to run a query on it or access it in some other way before you've explicitly reopened it.

- Colin.
 
Upvote 0

Alex_197

Well-Known Member
Licensed User
Longtime User
No. It's simply the folder "Download(s)", located in the root. No longer accessible (I think starting SDK30).

The shared folder you are probably using is the folder /Android/data/name of your application/...

have a look here, frustrated programmers

Worth trying to limit your app to Android 13 and try then. But I think if Android 15 or 16 comes out, you run into the same problems.
Open the database from within the assets is no option. It does not work and you only have read-access granted.

Maybe defining a save folder could be an option and copying it from the assets to that location and work with the file there...
Never tried that, switched from B4A to B4J because of that politics made by Google.
As I understand it, you have to ask the user for a safe location for granting the access rights. This does not override the blocked access to the general download folder or the data-folder of your app. In my opinion, most of the users are simply overwhelmed with that principle and irritated.

But let's see what others say, I am not an expert...
Maybe defining a save folder could be an option and copying it from the assets to that location and work with the file there...
That's exaclty whay my app does - copy the database from the asset folder to rp.GetSafeDirDefaultExternal("") first and then open it. No permissions need to use this filder. I'm using Android 14 on my Samsung S29.
 
Upvote 0

Alex_197

Well-Known Member
Licensed User
Longtime User
You followed DonManfred's advice with asking for a runtimepermission? This has to be included also within the program's code, not (only) in manifest.

Defining...:
Public RP As RuntimePermissions

Only a small example how to implement a runtimepermission:
    RP.CheckAndRequest(RP.PERMISSION_READ_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result Then
        If File.Exists(SharedFolder,"Config.dta")=True Then
            Dim Count As Int
            Dim Readout As String
            Readout = File.ReadString(SharedFolder,"Config.dta")
            For i = 0 To Readout.Length-1
                If Readout.CharAt(i) = ";" Then
                    Count = Count+1
                End If
            Next
            Log ("Count="&Count)
                Log (Readout)
'                File.WriteString(SharedFolder,"Config.dta",Readout&";0")
'                Sleep(0)
'                RestorePersonal
'                BSave_Click
        End If
    End If
Why do you use RP.PERMISSION_READ_EXTERNAL_STORAGE?
Why you don't use rp.GetSafeDirDefaultExternal("") - this one doesn't need any permissions. Read this Runtime Permissions (Android 6.0+ Permissions)
 
Upvote 0

Pedro Caldeira

Active Member
Licensed User
Longtime User
I Have the permissions in the code also, the problem is not that. And if I set the target to 34, I don't get the error anymore, I get another relating to a foreground reference in the services. I have to take it step by step a address all the errors I have.
 
Upvote 0

CyberDroidWare

Member
Licensed User
Had to deal with that too.
The following is not prooved, only an idea what happened:

Google implemented a mechanism in Android 14, that prevents running of an app with a fairly "outdated" SDK-Level. I had to change the TARGET-SDK-Level from 29 to the now recommended level (think it is 33 now, there should be a message within the IDE). Then it started without that message on Android 14.

The problem with my app: It runs without this message on SDK33 but is useless from now on, because there is no longer access to the download-folder. The download-folder was the place for interchanging downloaded stuff, the app works with. I see no workaround for this, there will be no further development of this app for Android.

It is like it is, the automatic pick-up from that place of communication interchange is no longer an option because of security. Most users never had a problem with that, but have a problem with newly established delivery methods of the downloaded file (defining a save folder and so on.) So it would be a waste of time for me to continue my project. Sad as it is. Thank you Google. If this is not a problem with your application, you are lucky.
From my experience, you can read and write storage that you own but you are right, they have done away with external storage permissions in SDK 34+
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
As I understand it, you have to ask the user for a safe location for granting the access rights. This does not override the blocked access to the general download folder or the data-folder of your app. In my opinion, most of the users are simply overwhelmed with that principle and irritated.
If you use a ContentResolver, the default location is the downloads folder. The user only has to hit OK once & then every time you use the ContentResolver after that, it remembers that the user granted permission. It's pretty straightforward.

- Colin.
 
Upvote 0
Top