androidandroid-studioandroid-application-class

Run time permission from application


I want to ask for permission from the application class. How can I ask permission for accessing the device ID? I cannot ask for permission from activity as it crashes before starting the splash screen activity. The following code is part of splash screen activity.

 @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    checkpermi();

The code for checking permission

public  void checkpermi() {    
if(ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
            + ContextCompat.checkSelfPermission(
            this,Manifest.permission.READ_PHONE_STATE)
            + ContextCompat.checkSelfPermission(
            this,Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED){

        // Do something, when permissions not granted
        if(ActivityCompat.shouldShowRequestPermissionRationale(
                this,Manifest.permission.ACCESS_FINE_LOCATION)
                || ActivityCompat.shouldShowRequestPermissionRationale(
                this,Manifest.permission.READ_PHONE_STATE)
                || ActivityCompat.shouldShowRequestPermissionRationale(
                this,Manifest.permission.WRITE_EXTERNAL_STORAGE)){
            // If we should give explanation of requested permissions

            // Show an alert dialog here with request explanation
            AlertDialog.Builder builder = new AlertDialog.Builder(SplashScreenActivity.this);
            builder.setMessage("Location, Read Contacts and Write External" +
                    " Storage permissions are required to do the task.");
            builder.setTitle("Please grant those permissions");
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    ActivityCompat.requestPermissions(
                            SplashScreenActivity.this,
                            new String[]{
                                    Manifest.permission.ACCESS_FINE_LOCATION,
                                    Manifest.permission.READ_PHONE_STATE,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                            },

                            STORAGE_PERMISSION_CODE
                    );
                }
            });
            builder.setNeutralButton("Cancel",null);
            AlertDialog dialog = builder.create();
            dialog.show();
        }else{
            // Directly request for required permissions, without explanation
            ActivityCompat.requestPermissions(
                    this,
                    new String[]{
                            Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.READ_PHONE_STATE,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                    },
                    STORAGE_PERMISSION_CODE
            );
        }
    }else {
        // Do something, when permissions are already granted
        Toast.makeText(SplashScreenActivity.this,"Permissions already granted",Toast.LENGTH_SHORT).show();
    }
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    //Checking the request code of our request
    if(requestCode == STORAGE_PERMISSION_CODE){

        //If permission is granted
        if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){

            //Displaying a toast
            Toast.makeText(this,"Permission granted now you can read the storage",Toast.LENGTH_LONG).show();
        }else{
            //Displaying another toast if permission is not granted
            Toast.makeText(this,"Oops you just denied the permission",Toast.LENGTH_LONG).show();
        }
    }
}

But instead of opening the splash screen activity the on create method overrides with the on create method of the Collect.java application class and the codes are.

@Override
public void onCreate() {
    singleton = this;

    super.onCreate();

    PropertyManager mgr = new PropertyManager(this);


    mActivityLogger = new ActivityLogger(

            mgr.getSingularProperty(PropertyManager.DEVICE_ID_PROPERTY));
}

If I cannot delete the above code because most of the buttons inside the app won't work.

And the error logs are.

2020-02-27 16:36:12.159 31359-31359/com.gic.spade.android E/AndroidRuntime: FATAL EXCEPTION: main Process: com.gic.spade.android, PID: 31359 java.lang.RuntimeException: Unable to create application com.gic.spade.android.application.Collect: java.lang.SecurityException: getDeviceId: Neither user 10366 nor current process has android.permission.READ_PHONE_STATE. at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6065) at android.app.ActivityThread.-wrap1(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1764) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6944) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) Caused by: java.lang.SecurityException: getDeviceId: Neither user 10366 nor current process has android.permission.READ_PHONE_STATE. at android.os.Parcel.readException(Parcel.java:1959) at android.os.Parcel.readException(Parcel.java:1905) at com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId(ITelephony.java:5333) at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java:1069) at com.gic.spade.android.logic.PropertyManager.(PropertyManager.java:135) at com.gic.spade.android.application.Collect.onCreate(Collect.java:260) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1125) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6062) at android.app.ActivityThread.-wrap1(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1764)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6944)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) 


Solution

  • If you need a permission before you could even request the permission, maybe you should conclude that your code is not well architectured.

    Simply bypass that code until you can restart it when permissions are granted.

    In your question you seem to want to send the device ID when application is created. Just don't send it unless you have permission to get that.

    if (checkPermission(...) == GRANTED) {
        PropertyManager mgr = new PropertyManager(this);
        mActivityLogger = new ActivityLogger(mgr.getSingularProperty(PropertyManager.DEVICE_ID_PROPERTY));
    } else {
        mActivityLogger = new ActivityLogger();
        // Or even disable that logger altogether
    }