Potential Permissions Problems

P.S. The example given is not intended to be a full implementation just to illustrate the point that the ability to use conditional calls for permission in PermissionGranted and PermissionNotGranted blocks makes the automation task feasible and straightforward.

I would expect that all necessary permissions are requested without having to reload the screen several times.

In this example I have to reload the screen twice so that all permissions are granted and the sound is played:
permissions_test2.aia (106.1 KB)

PS : I put the sound file in the assets (for testing).

I'm talking about the "LocationSensor" component that requests "ACCESS_FINE_LOCATION", which is done automatically, without needing to be specifically requested (there is no need to ask on Screen.Initialize). In this case I have to reload the screen several times to get all needed permissions.
Your approach doen't work in this case, but maybe you can prove the opposite.

Yes, if I remove the LocationSensor component and use the BLE extension instead, it works.

PS: I only use components, no extension:

1 Like

Anke wrote: <Your approach doen’t work in this case, but maybe you can prove the opposite> .

Hi Anke,
I tested the location sensor component permission using a test method copied below and with the aia attached. I believe this confirms your finding that including the location sensor by itself over-rides/disables/bypasses a variety of permissions in the Screen1 initialisation.
Regards, Peter

Test method
It’s a stacked multi permission version of my earlier method. It had no other sensor than the location sensor and no extensions.In the test below I disabled the two Screen1.AskForPermission to ACCESS_FINE_LOCATION. instructions.

Test and results
On start up the test forced a request "Allow’Push to access this device’s location? DENY ALLOW ". (App Inventor calls all my apps ‘PushTo’). I tried denying and allowing the permission and in both cases the permissions in Screen1.Initialise were unable to run and I had to use a manual permission button to run the file permission that in turn ran the stacked permissions.
Without the location sensor the app worked either providing direct requests for permission or indirect requests to set permissions in the phone. I’ve attached an aia file in case my description is unclear to anyone.

The aia images
image
image
image

PermissionTest1.aia (22.2 KB)

1 Like

I carried out a different set of tests on the start up permission to ACCESS_FINE_LOCATION using labels and timers in the Screen1.initalise block and it seems clear that:

  • The independent start up permission to ACCESS_FINE_LOCATION takes priority over the Screen1 Initialise procedure.
  • No more than one permission request is allowed on the screen at a time.
  • Permission requests are not queued
  • The start up ACCESS_FINE_LOCATION request does not provide a PermissionGranted call back

I’m not a programmer so have to ask:

  • Are my dot point descriptions correct?
  • Do they reflect normal behaviour for a start up permission request?
  • Are there other start up permission requests that operate in the same way?
    and
  • Does this mandate the need for a manual trigger (e.g. list picker or button) to set permissions?

Thanks for any advice on this, Regards, Peter

1 Like

Exactly, so it's a bug.

1 Like

Yes, however, I noticed the following:

If I deny ACCESS_FINE_LOCATION, the Screen1.PermissionDenied event is triggered and eg WRITE_EXTERNAL_STORAGE is requested.

But of course that doesn't solve the problem and doesn't help in any way.

Yes. Let me explain more deeply:

Every component can optionally define an Initialize method that is called just prior to Screen's Initialize event. In the LocationSensor, this is used to request permission if it isn't granted. Since the permissions mechanism is modal, once we start a permission request the user needs to complete the workflow before the next request is made. Therefore, the presence of the LocationSensor (only if Enabled property is true) results in it being the first permission dialog shown. Further, because Screen's Initialize event is called immediately after the components initialize, the workflow hasn't been completed so the additional requests are ignored because one is already in progress.

Yes, but this is true of any Android app as the dialog is presented by the system, not the application.

Correct. As before, the goal here is that the developer shouldn't need to manage permissions at all. All of the components should request permission at the appropriate times and we have done a lot of auditing to try and ensure this is the case. The purpose of the AskForPermission block as envisioned was twofold: 1) Allow app developers to handle PermissionDenied events by explaining to the user (e.g., using the Notifier) why a permission was needed and then re-ask for permission and 2) allow an "escape hatch" for developers using extensions that needed dangerous permissions but had not been updated by their authors to use the new internal APIs we provided for extension developers. It was never intended to be used to request many permissions upfront as this is generally considered bad form in the app world (for example, Apple reserves the right to not publish apps that use this type of model if the permission isn't critical to the functioning of the app).

When we did the update to handle the permissions model, we decided not to call the PermissionsGranted event in the cases where the permission request was made at the request of a component as everything was "working as intended" in this scenario. That event is intended solely for explicit handling of requests made by calls to AskForPermission. On the other hand PermissionDenied could come from the user denying either an implicit or explicit permission request, so it is called in all scenarios.

On the one hand, the block was never intended to be used in this way but rather within the context of PermissionDenied. On the other hand, it seems like it might be useful to queue many calls to AskForPermission since inevitably people will misuse it in this way. Internally queuing the requests seems like the best option as it removes the management of the pending permission queue as a burden from the developer. However, we have to think about this interacts with the PermissionDenied event as now there is a potential interaction between having one or more permissions denied and needing UI to explain why permissions are needed.

1 Like

EWPatton wrote <It was never intended to be used to request many permissions upfront as this is generally considered bad form in the app world (for example, Apple reserves the right to not publish apps that use this type of model if the permission isn’t critical to the functioning of the app)>

Hi
Thanks for those explanations. I hadn’t realised that a request for multiple critical permissions upfront was considered bad form. I had hoped to avoid incoveniencing the app user by placing the requests at the start of a program so that it didn’t distract them when they were first learning to use the app. Would using a listpicker up front to request multiple critical permissions be acceptable? Otherwise I can include a suggestion in the read me document to alert the user to expect the requests during the app’'s operation unless they preempt this by setting the permissions up manually before using the app.
Regards, Peter

The way I’ve typically seen this done in other apps (mostly using iOS as an example since that’s my daily driver), is that they will show a screen explaining some functionality of the app “MyAwesomeApp helps you navigate to your favorite spots. We use your location to do so, but we need you to accept the next prompt for this to work.” (or something like that) with a next button that then causes the prompt to appear. Once they’ve accepted, you show another screen explaining the next thing, and so on. Generally though, it’s better to ask at the time when the permission is needed if it’s not critical to the functioning of the app.

Further reading:

1 Like

Thanks for the detailed explanations.
But why doesn’t this work specially with ACCESS_FINE_LOCATION?

Or in other words:
If multiple permissions are requested at Screen.Initialize (except ACCESS_FINE_LOCATION), they will be queried one after another. However, when ACCESS_FINE_LOCATION is requested at Screen.Initialize, more permissions on Screen.Initialize are no longer requested.

In the Screen1.Initialize block for my example I include multiple permission requests, but my tests showed that only one would be executed as they cannot be executed simultaneously and are not queued. This is whether or not the location sensor is in the app.
The reason I have the multiple requests at Screen.Initialize is so that if any permissions have not already been queried and granted then the first of these will be triggered and its corresponding PermissionGranted event will trigger a cyclical cascade of permission requests and PermissionGranted events until all are accepted or declined.

Then please post an AIA (which describes and explains the problem) so that I can reproduce it.

Hi Anke,I was suggesting an answer to your question <But why doesn’t this work specially with ACCESS_FINE_LOCATION> ? My suggestion arose from the tests I carried out before writing the example that I gave earlier - I should have posted the example again to make that clear so I’ve copied it below and supplied an aia as requested.

PermissionTest.aia (22.2 KB)

To clarify my previous post - When I place multiple Screen.AskPermission statements in a ScreenInitialisation block they are not queried one after another - only one is queried whether or not a Locationsensor component is present. I think this is normal operation as its been confirmed in the previous discussion that Permission requests are not queued.

PermissionTest4.aia (20.0 KB)
MultiPermissionsTest4

Hi Peter,

of course, this cannot work, since there are no components that require these permissions and therefore they were not declared in the Manifest.

These are the permissions declared in the Manifest in your app:
<uses-permission android: name = "android.permission.INTERNET" />
<uses-permission android: name = "android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android: name = "android.permission.ACCESS_WIFI_STATE" />
<uses-permission android: name = "android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />

These are missing:
<uses-permission android: name = "android.permission.WRITE_CALENDAR" />
<uses-permission android: name = "android.permission.READ_CALENDAR" />

You cannot request permissions without declaring them in the Manifest !

So you have to insert the components first to add these permissions to the Manifest and then call a function / method on Screen.Initialize.

Check this:
permissionsTest3.aia (105.7 KB)


1 Like

Hi Anke,
Thank you. I had misunderstood because the request WRITE_EXTERNAL_STORAGE worked whereas WRITE_CALENDAR and READ_CALENDAR didn't. The list you supplied of default permissions declared in the Manifest and your explanation were most helpful. And your aia showed me how multiple requests in the initialisation block can be called in sequence.

This leaves the question. Is there a critical requirement for the location sensor to request a permission just prior to Screen’s Initialize event. Or because it can interfere with a permission requested in the initialise event should the location sensor permission be moved to where it is first needed?

The example below has a ten second delay in Screen.Initialise before it calls for a WRITE_EXTERNAL_STORAGE permission request. If the location sensor's request for ACCESS_FINE_LOCATION permission is granted within ten seconds the WRITE_EXTERNAL_STORAGE permission request appears. If the location sensor's request is granted later than ten seconds delay the WRITE_EXTERNAL_STORAGE permission request doesn't appear demonstrating the interference mechanism.

PermissionTest5.aia (21.9 KB)


Regards, Peter

You should move it where it is first needed. The LocationSensor component requests permission due to its Enabled property being set to true. If you change it to false in the designer it won't prompt on startup. Then you can enable it in the blocks at the appropriate time and it will request permission at that point.

Properties of components are set before Screen1.Initialize is called, which is why you see it in the observed order.

2 Likes

Hi

Thanks to both EWPatton and Anke for their patience with all my questions and for their clear explanations and examples. They have made sense of a lot of what I was trying to understand. And of course that last instruction worked perfectly!

Greatly appreciated, Peter

3 Likes

Yes thanks, and I also learned something.

3 Likes