13

Marshmallow has redesigned getting permissions. So Handled permissions before calling the method which needs permissions and it works fine, but It crashes in the following scenario:

Step 1: Opened app and gave all the necessary permissions

Step 2: Clicked Home button(So the app is in background)

Step 3: Manually changed the permissions in the Settings

Step 4: Launched the app from multitasks, now it crashes because of app context becomes invalid

Observed that app gets created again, don't understand why this happens. Any suggestions to rectify this issue would be welcome!

ankuranurag2
  • 2,300
  • 15
  • 30
ABI
  • 1,536
  • 18
  • 38
  • Is there any exception?? If yes, you should handle it in try catch block – Onkar Nene May 11 '16 at 11:07
  • check this.... http://stackoverflow.com/questions/33488589/android-marshmallow-dynamic-permission-change-kills-all-application-processes – Nikunj May 11 '16 at 12:01
  • Spotted the issue, its because of the app gets recreated when we change permissions dynamically by keeping the app running in background, the context which I had used to access shared preferences becomes null – ABI Dec 26 '16 at 04:59

3 Answers3

1

It's because of additional features added from Marshmallow. You need to request from user at runtime. For this use this class which I have made. Then use it whereever required

public class AppPermission {

    public static boolean isMarshmallowPlusDevice() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;
    }

    @TargetApi(Build.VERSION_CODES.M)
    public static boolean isPermissionRequestRequired(Activity activity, @NonNull String[] permissions, int requestCode) {
        if (isMarshmallowPlusDevice() && permissions.length > 0) {
            List<String> newPermissionList = new ArrayList<>();
            for (String permission : permissions) {
                if (PackageManager.PERMISSION_GRANTED != activity.checkSelfPermission(permission)) {
                    newPermissionList.add(permission);
                }
            }
            if (newPermissionList.size() > 0) {
                activity.requestPermissions(newPermissionList.toArray(new String[newPermissionList.size()]), requestCode);
                return true;
            }
        }
        return false;
    }
}

Then put this code where you require permission from user.

if (!AppPermission.isPermissionRequestRequired(SignInActivity.this, new String[]{"android.permission.GET_ACCOUNTS"},
        REQUEST_APP_PERMISSION)) {
    // Your code if permission available
}

After this, in your Fragment or Activity put this code -

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case REQUEST_APP_PERMISSION:
            for (int i = 0; i < permissions.length; i++) {
                String permission = permissions[i];
                int grantResult = grantResults[i];
                switch (permission) {
                    case "android.permission.GET_ACCOUNTS":
                        if (PackageManager.PERMISSION_GRANTED == grantResult) {
                            // Your code
                        }
                        break;
                }
            }
            break;
    }
}

The above code is for request permission for GET_ACCOUNTS you can change it to whatever required.

Jimit Patel
  • 4,265
  • 2
  • 34
  • 58
  • then put some code if above doesn't suffice. The above code is mostly what all misses out – Jimit Patel May 11 '16 at 11:01
  • 4
    Its not code level issue that I'm facing, just want to make sure that app gets recreated when I change the permissions in Settings manually (while launching the app which is running in background, it gets crashed ) – ABI May 11 '16 at 11:10
  • @ABI : Was your problem solved by this? How did you able to handle the exception while resuming the app. – Himanshu Dwivedi Jul 12 '17 at 07:22
0

Observed that app gets created again, don't understand why this happens. Any suggestions to rectify this issue would be welcome!

Because when permissions change, application "state" should be invalidated. The proper way to do that is destroy the root context, which is the application itself.

You have to check the permissions granted status each time you query the API methods that require these permissions. You can't rely on some SharedPreferences flag indicating that "user granted the permissions in onboarding, ok, lets have fun". Make your app stateless in this regards.

For example, you can create some BaseActivity/BaseFragment or Utility and move all the checking logic in there.

Drew
  • 3,307
  • 22
  • 33
0

Define a boolean value at first

 private boolean isPermissionGranted = false;

And then check if permission granted:

if (!isPermissionGranted) {
        checkPermission();
    }

Actual code for run time permission check is as follow:

private void checkPermission() {
    int hasPermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.CAMERA);
    int hasWritePermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (hasPermission != PackageManager.PERMISSION_GRANTED && hasWritePermission != PackageManager.PERMISSION_GRANTED) {
        if (!ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.CAMERA) && !ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            showMessage(getString(R.string.allow_access_to_camera_external_storage),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                    REQUEST_CODE_ASK_PERMISSIONS);
                        }
                    });
            return;
        }
        ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
    } else {
        isPermissionGranted = true;
    }
}

private void showMessage(String message, DialogInterface.OnClickListener       listener) {
    new AlertDialog.Builder(UserProfile.this)
            .setMessage(message)
            .setPositiveButton(R.string.ok, listener)
            .setNegativeButton(R.string.cancel, null)
            .create()
            .show();
}

  @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_PERMISSIONS:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                isPermissionGranted = true;

            } else {
                isPermissionGranted = false;
                Toast.makeText(UserProfile.this, R.string.permission_denied, Toast.LENGTH_SHORT)
                        .show();
            }
            break;

        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

You can take reference from above code and implement it in your application.

Riten
  • 2,879
  • 3
  • 24
  • 28