-1

Here is my Permissions.java file

public class Permissions {
private Context mContext;
final int READ_COARSE_LOCATION = 20;

public Permissions(Context context) {
    mContext = context;
}

public void checkPermission() {
    ActivityCompat.requestPermissions((Activity) mContext, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, READ_COARSE_LOCATION);
}

public void showMaterialDialog() {
    MaterialDialog dialog;
    MaterialDialog.Builder builder = new MaterialDialog.Builder(this);
    builder.title("Permission needed")
            .content("This Action Requires the Location Setting to be enabled. Go to Settings and check the Location Permission inside the Permissions View")
            .positiveText("SETTINGS")
            .negativeText("CANCEL")
            .onPositive(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                    final Intent i = new Intent();
                    i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    i.addCategory(Intent.CATEGORY_DEFAULT);
                    i.setData(Uri.parse("package:" + getApplicationContext().getPackageName()));
                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                    i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                    startActivity(i);
                }
            })
            .onNegative(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                    dialog.dismiss();
                }
            });
    dialog = builder.build();
    dialog.show();
}

public void showDialogOK() {
    MaterialDialog dialog;
    MaterialDialog.Builder builder = new MaterialDialog.Builder(this);
    builder.title("Permission needed")
            .content("This permission is required to access the weather data of your location.")
            .positiveText("OK")
            .onPositive(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                    dialog.dismiss();
                }
            });
    dialog = builder.build();
    dialog.show();
}

public void permission_denied() {
    // permission was not granted
    // permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
    // shouldShowRequestPermissionRationale will return true
    //show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.ACCESS_COARSE_LOCATION)) {
        showDialogOK();
    } //permission is denied (and never ask again is  checked)
    //shouldShowRequestPermissionRationale will return false
    else {
        showMaterialDialog();
    }
}
}

The place where I am calling from an activity (WeatherActivity.java) (case R.id.location)

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.change_city : showInputDialog();
            break;
        case R.id.about_page : Intent intent = new Intent(WeatherActivity.this, AboutActivity.class);
            startActivity(intent);
            break;
        case R.id.refresh : changeCity(GlobalActivity.cp.getCity());
            break;
        case R.id.location :
            permission = new Permissions(this);
            permission.checkPermission();
            break;
    }
    return true;
}

Handling onRequestPermission result in my code is handled in the code given below (belonging to WeatherActivity.java) (RequestCode 20 is where I ask for Location Permission)

@Override
public void onRequestPermissionsResult(int requestCode,@NonNull String permissions[],@NonNull int[] grantResults) {
    switch (requestCode) {
        case 20: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                showCity();
            } else {
                permission.permission_denied();
            }
            break;
        }
    }
}

The problem is when I hit Deny (without Don't ask again selected) throws a NullPointer Exception as in :

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.PackageManager android.content.Context.getPackageManager()' on a null object reference
                                                                    at android.content.ContextWrapper.getPackageManager(ContextWrapper.java:91)
                                                                    at android.app.Activity.shouldShowRequestPermissionRationale(Activity.java:4167)
                                                                    at android.support.v4.app.ActivityCompatApi23.shouldShowRequestPermissionRationale(ActivityCompatApi23.java:54)
                                                                    at android.support.v4.app.ActivityCompat.shouldShowRequestPermissionRationale(ActivityCompat.java:419)
                                                                    at com.a5corp.weather.permissions.Permissions.permission_denied(Permissions.java:78)
                                                                    at com.a5corp.weather.activity.WeatherActivity.onRequestPermissionsResult(WeatherActivity.java:58)

Permissions.java line 78 is if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION))

WeatherActivity.java line 58 is permission.permission_denied()

But there is no problem when I click on Agree when the app asks for Permission. My piece of code runs properly then.

Sparker0i
  • 1,787
  • 4
  • 35
  • 60
  • 1
    **NEVER** create a random subclass of framework classes, like `Activity`. When you need a `Context` for something, use one that the framework hands to you. And, specifically for dealing with runtime permissions, `shouldShowRequestPermissionRationale()` needs to be called using an actual `Activity`, one that is registered in the manifest, was started by Android, and has gone through its `onCreate()` method. – CommonsWare Feb 24 '17 at 17:56
  • @CommonsWare so what you mean to say is that not to create a specific Permissions class as such? If yes, what if I need to read Permissions from another activity. Wouldn't I need to re write all that stuff again? – Sparker0i Feb 25 '17 at 01:17
  • Why did I even get a downvote on my question? – Sparker0i Feb 25 '17 at 01:18
  • 2
    @Sparker0i You can create a simple PermissionHandler that handles permission related stuff for your entire app. but you **don't need to extend Activity** here. You can pass context of your running activity in constructor. – phoenix Feb 25 '17 at 06:40
  • Oh dear, I did not see this.....I never had Activity extended in my code – Sparker0i Feb 25 '17 at 06:42

1 Answers1

1

Try to change your permission_denied method like below:

public void permission_denied() {
    // permission was not granted
    // permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
    // shouldShowRequestPermissionRationale will return true
    //show the dialog or snackbar saying its necessary and try again        otherwise proceed with setup.
        if (ActivityCompat.shouldShowRequestPermissionRationale(mContext,
                Manifest.permission.ACCESS_COARSE_LOCATION)) {
            showDialogOK();
        } //permission is denied (and never ask again is  checked)
        //shouldShowRequestPermissionRationale will return false
        else {
            showMaterialDialog();
        }
    }
}

Here you were passing your activity instance as a first parameter inside ActivityCompat.shouldShowRequestPermissionRationale, instead you need to pass context of your activity.

phoenix
  • 496
  • 3
  • 11