Mordred Mordred - 3 months ago 33
Android Question

camera crashes on startactcityforresult and onactivity result in turn fails

I am trying to upload images to firebase storage using the following

@AfterPermissionGranted(RC_STORAGE_PERMS)
private void launchCamera() {
Log.d(TAG, "launchCamera");

// Check that we have permission to read images from external storage.
String perm = Manifest.permission.WRITE_EXTERNAL_STORAGE;
if (!EasyPermissions.hasPermissions(this, perm)) {
EasyPermissions.requestPermissions(this, getString(R.string.rationale_storage),
RC_STORAGE_PERMS, perm);
return;
}


// Choose file storage location, must be listed in res/xml/file_paths.xml
File dir = new File(Environment.getExternalStorageDirectory() + "/photos");
File file = new File(dir, UUID.randomUUID().toString() + ".jpg");
try {
// Create directory if it does not exist.
if (!dir.exists()) {
dir.mkdir();
}
boolean created = file.createNewFile();
Log.d(TAG, "file.createNewFile:" + file.getAbsolutePath() + ":" + created);
} catch (IOException e) {
Log.e(TAG, "file.createNewFile" + file.getAbsolutePath() + ":FAILED", e);
}

// Create content:// URI for file, required since Android N
// See: https://developer.android.com/reference/android/support/v4/content/FileProvider.html
mFileUri = FileProvider.getUriForFile(this,
"com.mordred.youlift.fileprovider", file);



//this is my own set of fixes to grant permission to uri, not sure its neceary though, seems like overkill
Context context = this;
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, mFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
// Create and launch the intent
context.grantUriPermission(getPackageName(), mFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mFileUri);

//condition suggested by android developers
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, RC_TAKE_PICTURE);
}
}


the camera crashes when i take the picture and the app says 'taking picture failed' according to an if structure in my onactivityresult() function. here is its code

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data);
if (requestCode == RC_TAKE_PICTURE) {
if (resultCode == RESULT_OK) {
if (mFileUri != null) {
uploadFromUri(mFileUri);
} else {
Log.w(TAG, "File URI is null");
}
} else {
Toast.makeText(this, "Taking picture failed.", Toast.LENGTH_SHORT).show();
}
}
}


My stacktrace is

08-14 14:22:39.722 26970-26970/com.mordred.youlift D/PictureActivity: launchCamera
08-14 14:22:39.727 26970-26970/com.mordred.youlift I/dalvikvm: Could not find method android.app.Fragment.requestPermissions, referenced from method pub.devrel.easypermissions.EasyPermissions.executePermissionsRequest
08-14 14:22:39.727 26970-26970/com.mordred.youlift W/dalvikvm: VFY: unable to resolve virtual method 391: Landroid/app/Fragment;.requestPermissions ([Ljava/lang/String;I)V
08-14 14:22:39.727 26970-26970/com.mordred.youlift D/dalvikvm: VFY: replacing opcode 0x6e at 0x001d
08-14 14:22:39.727 26970-26970/com.mordred.youlift I/dalvikvm: Could not find method android.app.Fragment.shouldShowRequestPermissionRationale, referenced from method pub.devrel.easypermissions.EasyPermissions.shouldShowRequestPermissionRationale
08-14 14:22:39.727 26970-26970/com.mordred.youlift W/dalvikvm: VFY: unable to resolve virtual method 396: Landroid/app/Fragment;.shouldShowRequestPermissionRationale (Ljava/lang/String;)Z
08-14 14:22:39.727 26970-26970/com.mordred.youlift D/dalvikvm: VFY: replacing opcode 0x6e at 0x001c
08-14 14:22:39.727 26970-26970/com.mordred.youlift W/EasyPermissions: hasPermissions: API version < M, returning true by default
08-14 14:22:39.742 26970-26970/com.mordred.youlift D/PictureActivity: file.createNewFile:/storage/sdcard0/photos/a520231b-ff0c-435d-a3db-a3e9816d6726.jpg:true
08-14 14:22:42.682 26970-26970/com.mordred.youlift W/IInputConnectionWrapper: showStatusIcon on inactive InputConnection
08-14 14:23:26.567 26970-26983/com.mordred.youlift E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading android.support.v4.content.FileProvider uri content://com.mordred.youlift.fileprovider/external/a520231b-ff0c-435d-a3db-a3e9816d6726.jpg from pid=27383, uid=1000 requires the provider be exported, or grantUriPermission()
at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:332)
at android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:250)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:236)
at android.os.Binder.execTransact(Binder.java:367)
at dalvik.system.NativeStart.run(Native Method)


08-14 14:23:27.597 26970-26970/com.mordred.youlift D/PictureActivity: onActivityResult:101:0:null

Answer

First, your loop over activities is for ACTION_SEND, which is not doing you any good, as you are using ACTION_IMAGE_CAPTURE.

Second, add Intent.FLAG_GRANT_WRITE_URI_PERMISSION to takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);.

Also note that you only need to do one of those: addFlags() or grantUriPermission(), depending on OS version:

  if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) {
    i.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  }
  else {
    List<ResolveInfo> resInfoList=
      getPackageManager()
        .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY);

    for (ResolveInfo resolveInfo : resInfoList) {
      String packageName = resolveInfo.activityInfo.packageName;
      grantUriPermission(packageName, outputUri,
        Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
          Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
  }

(where i is the ACTION_IMAGE_CAPTURE Intent)

Here is the full activity where that code comes from.