Search code examples
androidindexoutofboundsexceptionandroid-jetpack

androidx ActivityResultContracts.RequestPermission seems to have issue on cancelled request


I'm using androidx.activity:activity:1.2.0-alpha8 when requesting permission with the code

val request = registerForActivityResult(ActivityResultContracts.RequestPermission()) { res ->
    if (res != null && res) {
      // Permission granted, proceed
    } else {
      UiUtils.showToastSafe(this, R.string.necessary_permission_needed)
    }
}
request.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)

It ended up with a crash on Huawei Mate10, with the stack trace as follows:

Failure delivering result ResultInfo{who=@android:requestPermissions:, request=65538, result=0, data=null} to activity {com.baicizhan.x.shadduck/com.baicizhan.x.shadduck.homepagePhone.PhoneHomepageActivity}: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0

androidx.activity.result.contract.ActivityResultContracts$RequestPermission in parseResult at line 265
androidx.activity.result.contract.ActivityResultContracts$RequestPermission in parseResult at line 251
androidx.activity.result.ActivityResultRegistry in doDispatch at line 313
androidx.activity.result.ActivityResultRegistry in dispatchResult at line 277
androidx.activity.ComponentActivity in onRequestPermissionsResult at line 597
androidx.fragment.app.FragmentActivity in onRequestPermissionsResult at line 579
android.app.Activity in dispatchRequestPermissionsResult at line 8567
android.app.Activity in dispatchActivityResult at line 8417
android.app.ActivityThread in deliverResults at line 5464
android.app.ActivityThread in handleSendResult at line 5512
...

It seems like the request permission Intent was cancelled, and the Activity would dispatch an int[0] as the result(based on platform 29 source code):

private void dispatchRequestPermissionsResult(int requestCode, Intent data) {
    mHasCurrentPermissionsRequest = false;
    // If the package installer crashed we may have not data - best effort.
    String[] permissions = (data != null) ? data.getStringArrayExtra(
      PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES) : new String[0];
    final int[] grantResults = (data != null) ? data.getIntArrayExtra(
      PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS) : new int[0];
    onRequestPermissionsResult(requestCode, permissions, grantResults);
}

And the result parsing part in the RequestPermission goes as follows...

@NonNull
@Override
public Boolean parseResult(int resultCode, @Nullable Intent intent) {
    if (intent == null || resultCode != Activity.RESULT_OK) return false;
    int[] grantResults = intent.getIntArrayExtra(EXTRA_PERMISSION_GRANT_RESULTS);
    if (grantResults == null) return false;
    return grantResults[0] == PackageManager.PERMISSION_GRANTED;
}

Is it the reason I got this crash or am I missing something?

See Also Juan Cruz Soler's answer to another similar crash


Solution

  • As per this issue, the RequestPermission code was fixed in 1.2.0-alpha07 to check the length of the array that was returned. Please upgrade to alpha07 or higher.