Monday, September 12, 2016

Android Request Run-Time Permission Example

Although Android is being keep developed but the latest update to Android M is totally different since there is some major change that would change everything like new Run-time Permission. Surprisingly it is not much talked about in Android Developer community even though it is extremely important and may cause some big trouble in the near future.

The New Runtime Permission
Android's permission system is one of the biggest security concern all along since those permissions are asked for at install time. Once installed, the application will be able to access all of things granted without any user's acknowledgement what exactly application does with the permission.

No surprise why there are so many bad guys trying to collect user's personal data through this security weakness and use it in the bad way.

Android team also know this concern. 7 year passed, finally permission system is redesigned. In Android 6.0 Marshmallow, application will not be granted any permission at installation time. Instead, application has to ask user for a permission one-by-one at runtime.

Note: Please note that permission request dialog shown above will not launch automatically. Developer has to call for it manually. In the case that developer try to call some function that requires a permission which user has not granted yet, the function will suddenly throw an Exception which will lead to the application crashing.

What happened to the application that has already been launched?
This new permission system may cause you some panic right now. "Hey ! What's about my application that launched 3 years ago. If it is installed on Android 6.0 device, does this behavior also applied? Will my application also crash?!?"

Don't worry. Android team has already thought about it. If the application's targetSdkVersion is set to less than 23. It will be assumed that application is not tested with new permission system yet and will switch to the same old behavior: user has to accept every single permission at install time and they will be all granted once installed !

As a result, application will run perfectly like previous. Anyway please note that user still can revoke a permission after that ! Although Android 6.0 warn the user when they try to do that but they can revoke anyway.

Very Simple Code Solution:

Manifest.xml: 


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.myandrioid.abhinaw">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <application 
       android:allowBackup="true" 
       android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name" 
       android:supportsRtl="true"  
      android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>



MainActivity.java :

package com.myandrioid.abhinaw;
import android.Manifest;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
{
    private Button buttonRequestPermission;
    private int STORAGE_PERMISSION_CODE = 23;

    @Override    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        requestPermisssion();
    }

    private  void requestPermisssion()
    {
        buttonRequestPermission = (Button) findViewById(R.id.buttonRequestPermission);
        buttonRequestPermission.setOnClickListener(new View.OnClickListener()
        {
            @Override            public void onClick(View v)
            {
                if(isReadStorageAllowed())
                {
                    Toast.makeText(MainActivity.this,"You already have the permission",Toast.LENGTH_LONG).show();
                    return;
                }
                requestStoragePermission();
            }
        });
    }

    private boolean isReadStorageAllowed()
    {
        int result = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
        if (result == PackageManager.PERMISSION_GRANTED)
            return true;
        return false;
    }

    private void requestStoragePermission()
    {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_EXTERNAL_STORAGE))
        {
           // do nothing
        }
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},STORAGE_PERMISSION_CODE);
    }

    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
    {
        if(requestCode == STORAGE_PERMISSION_CODE)
        {
            if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(this,"Permission granted now you can read the storage",Toast.LENGTH_LONG).show();
            }
            else            {
                Toast.makeText(this,"Oops you just denied the permission",Toast.LENGTH_LONG).show();
            }
        }
    }
}

activity_main.xml :

<Button  
  android:layout_width="match_parent" 
   android:layout_height="wrap_content" 
   android:text="Request Storage Permission"  
  android:id="@+id/buttonRequestPermission"  
  android:layout_centerVertical="true"  
  android:layout_below="@+id/button" />

Result: 







No comments: