Android Tutorial Runtime Permissions (Android 6.0+ Permissions)

Discussion in 'Tutorials & Examples' started by Erel, Jun 8, 2016.

Similar threads

B4A Tutorial GPS tutorial
B4A Tutorial Integrating Firebase Services
B4A Question RuntimePermission
B4A Tutorial Intent Based Camera
B4A Tutorial DBUtils - Android databases are now simple!
  1. Erel

    Erel Administrator Staff Member Licensed User

    This is an optional feature. It is only relevant if android:targetSdkVersion is set to 23 or above.
    If the targetSdkVersion is lower than 23 then the standard permissions system will be used on all devices including Android 6+.

    B4A v6.0 (which was not yet released) adds support for runtime permissions. The nice thing about runtime permissions is that the user is not asked for any permission when they install your application from Google Play. Instead they will be asked to approve "dangerous" permissions at runtime.

    Luckily most permissions are not considered dangerous. You can see the list of permissions that are considered dangerous here: https://developer.android.com/guide/topics/security/permissions.html#perm-groups

    Requesting permissions at runtime

    Example:
    Code:
    Sub Process_Globals
       
    Private rp As RuntimePermissions
    End Sub

    Sub Globals
       
    Private gmap As GoogleMap
       
    Private MapFragment1 As MapFragment
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("1")
    End Sub

    Sub MapFragment1_Ready
       gmap = MapFragment1.GetMap
       rp.CheckAndRequest(rp.PERMISSION_ACCESS_FINE_LOCATION)
    End Sub

    Sub Activity_PermissionResult (Permission As String, Result As Boolean)
       
    If Permission = rp.PERMISSION_ACCESS_FINE_LOCATION Then
         gmap.MyLocationEnabled = Result
       
    End If
    End Sub
    RuntimePermissions.CheckAndRequest is the key method.

    The method (simplified) logic:
    Code:
    If <user has already approved> Or <older device> Then
    Activity_PermissionResult (Permission, 
    True)
    Else
    ShowDialog
    Activity_PermissionsResult (Permission, Dialog result)
    End If
    CheckAndRequest is not a blocking method. The program flow will continue and only later Activity_PermissionsResult will be raised.

    upload_2016-6-8_14-48-39.png

    The CheckAndRequest method can only be called from an Activity.
    There is another method named Check that only tests whether the permission has already been approved or not. This method can be called from any module.
    It might be tempting to first test whether there is a permission and only if there is no permission call CheckAndRequest. However it will just make the program flow more complicated as you will need to deal with all cases anyway.
    As a general rule, you shouldn't call RuntimePermissions.Check from an Activity. It will be simpler to always call CheckAndRequest.

    Listing the permissions

    Not many are aware to the fact that you can see the project permissions by clicking on the List Permissions button that is inside the Logs tab:

    [​IMG]

    The dangerous permissions are marked with * (in B4A v6+).
    You don't need to ask for non-dangerous permissions.

    READ_EXTERNAL_STORAGE / WRITE_EXTERNAL_STORAGE

    This is the most common dangerous permission. It is added automatically when you use File.DirDefaultExternal or File.DirRootExternal.
    However there is a simple workaround for this.

    1. Use RuntimePermissions.GetSafeDirDefaultExternal("") instead of File.DirDefaultExternal. The parameter passed is an optional subfolder that will be created under the default folder.

    2. Add this code to the manifest editor:
    Code:
    AddManifestText(
    <uses-permission
      android:name=
    "android.permission.WRITE_EXTERNAL_STORAGE"
      android:maxSdkVersion=
    "18" />
    )
    The explanation for this is that GetSafeDirDefaultExternal doesn't require any permission on Android 4.4+ (API 18) and requires the WRITE_EXTERNAL_STORAGE on older versions. The code above adds the permission to older devices.

    You only need to deal with WRITE_EXTERNAL_STORAGE at runtime if you need access to a folder other than the app's default external folder.

    Notes & tips:

    - You can only request permissions that were declared in the manifest file (this is usually taken care by the compiler).
    - Testing the permissions can be confusing as the user only needs to give permissions once. The solution is to uninstall the app from the device. Click on Ctrl + P (clean project) in the IDE and run again.
    - The user actually approves groups of permissions. So if the user has approved the read contacts permission they will not be asked to approve the write contacts permission.
    - Once you've uploaded your app to Google Play with targetSdkVersion set to 23 you cannot downgrade the target version back.
     
    Last edited: Jun 9, 2016
    koaunglay, fredo, MarcoRome and 6 others like this.
  2. somed3v3loper

    somed3v3loper Well-Known Member Licensed User

    Now you reached Android version :)
    When should we expect B4A ?
    Thanks again for your support .
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    As this is a tutorial please start a new thread for any unrelated question (BTW, my Android device run Android 7.0 ;) ).
     
  4. ilan

    ilan Expert Licensed User

    hi @Erel, once the user has accepted the permission will he be asked again when the next time the app will perform the same task?

    thanx


    ok no need to answer have seen this now

    Code:
    If <user has already approved> Or <older device> Then
    Activity_PermissionResult (Permission, 
    True)
    Else
    ShowDialog
    Activity_PermissionsResult (Permission, Dialog result)
    End If
     
  5. scrat

    scrat Active Member Licensed User

    Hello,

    is it possible to request multiple permissions at once ?
    Check and CheckAndRequest accept string, is it possible tp pass an array or a list ?

    Thanks
     
  6. Erel

    Erel Administrator Staff Member Licensed User

    You can call CheckAndRequest multiple times. The permissions are always presented separately to the user.
     
  7. ilan

    ilan Expert Licensed User

    hi

    i dont understand how to implement it in my app

    i want to request all dangerous at the first start (because i use some via service and dont want to ask them when the service is running in background)

    how can i do it?
     
  8. ilan

    ilan Expert Licensed User

    ok just found out that when i check "RuntimePermission" and try to build the app i get an error something with Admob lib...

    when i uncheck again runtime permission it works so there is a conflict between both libs.
     
  9. Erel

    Erel Administrator Staff Member Licensed User

    ilan likes this.
  10. ilan

    ilan Expert Licensed User

  11. Cebuvi

    Cebuvi Member Licensed User

    Hello Erel,

    I'm trying to manage permissions in appĀ“s and I started with the example of this tutorial.
    I do not get it to work and I do not understand where the problem is.
    I attached the zip program to see if you can help me find the solution.
    Thank you.

    Cesar
     

    Attached Files:

  12. Erel

    Erel Administrator Staff Member Licensed User

    Please start a new thread in the questions forum.
     
  13. FabioG

    FabioG Active Member Licensed User

    Hi,

    when I add the "Runtime Permissions" library an error (see image attacched) telling me not to find android-support-v4.jar
    the file is added to the external libraries folder

    some advice ?
     

    Attached Files:

  14. AndOrNot

    AndOrNot Active Member Licensed User

    Have you copy android-support-v4.jar into b4a libraries from sdk?
     
  15. FabioG

    FabioG Active Member Licensed User

    yes copyed from my sdk folder "D:\Android\android-sdk\extras\android\support\v4"
     
  16. Erel

    Erel Administrator Staff Member Licensed User

  17. FabioG

    FabioG Active Member Licensed User

    solved!

    Thanks Erel
     
  18. susu

    susu Well-Known Member Licensed User

    How can I request for permission SYSTEM_ALERT_WINDOW (Draw over other apps) ? It's not exist in RuntimePermissions.

    Some thing like this code:
    Code:
    public static void requestSystemAlertPermission(Activity context, Fragment fragment, int requestCode) {
        
    if (VERSION.SDK_INT < VERSION_CODES.M)
            
    return;
        final 
    String packageName = context == null ? fragment.getActivity().getPackageName() : context.getPackageName();
        final 
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + packageName));
        
    if (fragment != null)
            fragment.startActivityForResult(
    intent, requestCode);
        
    else
            context.startActivityForResult(
    intent, requestCode);
    }

    Then, in the onActivityResult, you can check if the permission is given or not, as such:

    @TargetApi(VERSION_CODES.M)
    public static boolean isSystemAlertPermissionGranted(Context context) {
        final boolean result = VERSION.SDK_INT < VERSION_CODES.M || Settings.canDrawOverlays(context);
        return result;
    }
    Link: http://stackoverflow.com/questions/...ng-auto-granted-on-some-pre/33895409#33895409
     
  19. Erel

    Erel Administrator Staff Member Licensed User

  20. susu

    susu Well-Known Member Licensed User

    If set targetSdkVersion to 23 and not accepted permission "Draw on top", my app crash with error:
    android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@eed4eed -- permission denied for this window type

    I want to check if permission "Draw on top" is not accepted, it will call "Draw over other apps" setting like image below.

    [​IMG]
     
Loading...