Runtime permission in Android

In my last tutorial, We had practiced awesome features of RxJava in Android. Here are the link details RxJava in android part1, RxJava in android part2 and MVP with RxJava.

Today we got one more day to learn something more. Let's make this day more awesome to learn something new. In this article, we will learn why runtime permission and how to give permission at runtime in the application. Earlier we have practiced that the user can be seen the permission detail at while installing the app. But in marshmallow device version 6.0 it has changed. Now application will not be granted the permission while installing the application. It will ask users at runtime. Why this is required? 


In the previous below the marshmallow versions like the lollipop and other lower version devices, User was felt like obvious to see the permission details while installing that, They might be thinking that why can I shared my confidential information without asking that permission. The application should be asked me, hey if you want to access those then please grant me permission to access. For example, if any other app wants to get access the phone contact then user feel obvious to give access those. That why it comes runtime permission. If the other application wants to access phone contact of users then its all depend on the user if they granted the permission or not. If the user has not granted then other application will not be allowed to access that information.


One common question of every developer that how android take care our old application launch on marshmallow device. So I would say do not panic be relaxed android take care that issue very smartly. If your application has built on targetsdkversion is less than 23 then it should not be crashed on Android M. It will work fine without any issue. Runtime permission will only ask users if you build the app on target SDK version 23 or higher. 


This really sounds good for the users to feel confidence that my phone is secure if I used to install any other application without any issue. Android take care security point of view at the top priority. Awesome:)


Okay, Let's see what are those permissions is granted while installing the application. These permissions called protection-level permission. It will not ask the user at runtime.

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

Great. This permission is required to add in Android manifest file then it works fine without any crash. Now let's check what are required to check the permission if my target SDK version and compile SDK version is 23 or higher.

A developer needs to follow three basic methods.
1. checkSelfPermission(Permission) - to check the permission is already granted or not.
2. requestPermissions(String [] permissions, int requestCode) - if not then request for permission
3. onRequestPermissionsResult(int premsRequestCode, String [] permissions, int [] grantResults) - to check the result whether permission is granted or not.

Let's see one example I am building an app which targets SDK version is 23 or higher. I want location access in one of my application. First of all, you need to know what are permission is required for access the Location. Okay, How do I make sure? Let's check in framework level what Gooogle has defined for location access?
When I look this file DefaultPermissionGrantPolicy.java in framework module.
I found this permission is required to access the location.

 private static final Set<String> LOCATION_PERMISSIONS = new ArraySet<>();
109    static {
110        LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
111        LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
112    }


So basically these two permission is required to access Location. Ok, Let's check while clicking on a button I want to access the location.

import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.Toast;

import com.sunil.mvprxjavaapp.R;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * Created by sunil on 08-04-2017.
 */

public class RunTimePermissionTestActivity extends AppCompatActivity {

    @BindView(R.id.RuntimeButton)
    Button RuntimeButton;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_runtime_permission);
        ButterKnife.bind(this);

    }

    @OnClick(R.id.RuntimeButton)
    public void RunTimeClick(){

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                //Location Permission already granted or not
                tryToGetLocationValue();
            } else {
                //Request Location Permission
                askLocationPermission();
            }
        }
        else {
           // not required any runtime permission for below M
            tryToGetLocationValue();
        }
    }

    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
    private void askLocationPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)) {

                // Show an explanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission. This info convince to users to allow
                new AlertDialog.Builder(this)
                        .setTitle("Location Permission Needed")
                        .setMessage("This app needs the Location permission, please accept to use location functionality")
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                //Prompt the user once explanation has been shown to ask for permission again
                                ActivityCompat.requestPermissions(RunTimePermissionTestActivity.this,
                                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                        MY_PERMISSIONS_REQUEST_LOCATION );
                            }
                        })
                        .create()
                        .show();


            } else {
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION );
            }
        }
    }

    private void tryToGetLocationValue() {
        Toast.makeText(this, "Good to go to fetch location", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission is granted
                    // location-related task you need to do.
                    if (ContextCompat.checkSelfPermission(this,
                            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

                         tryToGetLocationValue();
                    }

                } else {

                    // permission denied
                    Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
                }
                return;
            }

        }
    }
}

Add this line in Android Manifest file.

 
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">

Great You did well. It does not require to check permission for both ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION. Android document said you can allow only one permission is enough for access but need to add both permissions in the android manifest file.




You can see about snaps, It will ask for the user to allow or deny. If a user has denied press and again he tries to access location while clicking on the button it prompts to the user to need permission access to user location functionality. Then this time prompts shows with check box never ask again. If the user has checked this box it means user not interested in allowing this permission and not interested in using location feature anymore.

Thanks for reading this post.

Comments

  1. Hi, I read your blog this is very informative. Thanks for share this blog. You can find dedicated Web designers,Mobile Application Developers,Ecommerce Solution, SEO and marketing specialists will tailor make the solution you want for your business.Know more about click here – www.hvantagetechnologies.com

    ReplyDelete
  2. Hai Author Good Information that i found here,do not stop sharing and Please keep

    updating us..... Thanks

    ReplyDelete
    Replies
    1. Thanks Vamshi, I will keep updating and thanks for appreciation.

      Delete

  3. Wonderful blog.. Thanks for sharing informative Post. Its very useful to me.

    Installment loans
    Payday loans
    Title loans

    ReplyDelete

Post a Comment

Popular posts from this blog

Service LifeCycle

NavigationView Drawer Expandable menu Item in ANdroid

Custom SeekBar (Discrete SeekBar) in android