无法在Android 11上以编程方式拍照 – 意图返回已取消状态。

huangapple go评论68阅读模式
英文:

Cannot take a photo programmatically on Android 11 - intent returns canceled status

问题

开始一个意图:

  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  CurrentFile = new File(getTempFileString());
  CurrentUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", CurrentFile);
  intent.putExtra(MediaStore.EXTRA_OUTPUT, CurrentUri);
  intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
  startActivityForResult(intent, IMAGE_CAPTURE);

以前是有效的,但现在不再有效。在意图之后启动的方法是:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
}

resultCode 以前是 RESULT_OK,但现在是 RESULT_CANCELED

如果我停止检查 resultCode,并继续执行,我发现照片不存在。

根据 CommonsWare 的评论,我提取了日志。在此操作期间生成的 654 行日志中,有四行似乎与问题有关。

2020-10-12 11:03:04.301 1471-1763/? E/MediaProvider: 不允许创建非默认顶级目录或删除现有目录!
2020-10-12 11:03:04.310 477-2112/? I/AppsFilter: 交互:PackageSetting{240e1c6 com.[我的应用程序包名]/10151} -> PackageSetting{193734c com.android.camera2/10124} 被阻止
2020-10-12 11:03:04.553 390-9884/? W/ServiceManager: 权限失败:android.permission.SYSTEM_CAMERA,来自 uid=10124 pid=11746
2020-10-12 11:03:14.097 11746-11746/? E/CAM_StateSavePic: 在保存结果到 URI 时出现异常:Optional.of(content://[我的应用程序包名].provider/external_files/[我请求的SD卡路径]/1602518584301.jpg)

我正在请求将文件保存在这里:

new File(Environment.getExternalStorageDirectory(), getString(a.getApplicationInfo().labelRes))

这似乎是问题所在。

英文:

Starting an intent:

  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  CurrentFile = new File(getTempFileString());
  CurrentUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", CurrentFile);
  intent.putExtra(MediaStore.EXTRA_OUTPUT, CurrentUri);
  intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
  startActivityForResult(intent, IMAGE_CAPTURE);

Used to work. It no longer does. My method that starts after the intent is:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
}

The resultCode used to be RESULT_OK but is now RESULT_CANCELED.

If I stop checking the resultCode and just go past this, I find that the photo doesn't exist.

Based on CommonsWare's comment I extracted the logs. Of the 654 lines generated during this operation, four seem relevant.

2020-10-12 11:03:04.301 1471-1763/? E/MediaProvider: Creating a non-default top level directory or deleting an existing one is not allowed!
2020-10-12 11:03:04.310 477-2112/? I/AppsFilter: interaction: PackageSetting{240e1c6 com.[my app package]/10151} -> PackageSetting{193734c com.android.camera2/10124} BLOCKED
2020-10-12 11:03:04.553 390-9884/? W/ServiceManager: Permission failure: android.permission.SYSTEM_CAMERA from uid=10124 pid=11746
2020-10-12 11:03:14.097 11746-11746/? E/CAM_StateSavePic: exception while saving result to URI: Optional.of(content://[my app package].provider/external_files/[The SD card path I asked for]/1602518584301.jpg)

I am asking the file to get saved here:

new File(Environment.getExternalStorageDirectory(), getString(a.getApplicationInfo().labelRes))

This seems to be the issue.

答案1

得分: 12

Truly @CommonsWare deserves the credit here. The issue was the getTempFileString() call in the source code. I was attempting to save the file to a temp path so I could delete it right after. The file only exists shortly. Google blocked access to this. The Camera application received an error about not being able to save to this path, however it did not throw an error or display a message. It just returned a result of RESULT_CANCELED back to my application. I fixed this by updating the path used to the local cache directory getExternalCacheDir() and am using a sub directory inside that.

Edit: Adding the code that worked for me. Removed app specific text, and the error handling to keep it short and simple.

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "My Application Directory");

if (!path.exists()) {
   path.mkdir();
}

File imageFile = File.createTempFile("Your file Name", ".jpg", path);

Context context = getActivity().getBaseContext();
Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", imageFile);

intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
   String packageName = resolveInfo.activityInfo.packageName;
   context.grantUriPermission(packageName, CurrentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

startActivityForResult(intent, IMAGE_CAPTURE); // IMAGE_CAPTURE = 0

(以上为翻译结果,已排除代码部分。)

英文:

Truly @CommonsWare deserves the credit here. The issue was the getTempFileString() call in the source code. I was attempting to save the file to a temp path so I could delete it right after. The file only exists shortly. Google blocked access to this. The Camera application received an error about not being able to save to this path, however it did not throw an error or display a message. It just returned a result of RESULT_CANCELED back to my application. I fixed this by updating the path used to the local cache directory getExternalCacheDir() and am using a sub directory inside that.

Edit: Adding the code that worked for me. Removed app specific text, and the error handling to keep it short and simple.

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), &quot;My Application Directory&quot;);

if (!path.exists()) {
   path.mkdir();
}

File imageFile = File.createTempFile(&quot;Your file Name&quot;, &quot;.jpg&quot;, path);

Context context = getActivity().getBaseContext();
Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + &quot;.provider&quot;, imageFile);

intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

List&lt;ResolveInfo&gt; resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
   String packageName = resolveInfo.activityInfo.packageName;
   context.grantUriPermission(packageName, CurrentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

startActivityForResult(intent, IMAGE_CAPTURE); // IMAGE_CAPTURE = 0

答案2

得分: 1

你不应该使用 "getExternalStoragePublicDirectory()",因为这是共享存储行为,并且从(可能是)2021年7月5日起,Play Store 上的所有应用程序必须针对 Android SDK 30 进行目标设置,只能使用 Scoped Storage(因此无法使用 "requestLegacyStorage",我不清楚 "preserveLegacyStorage")。

我建议你将目标路径更改为:

context.getExternalFilesDir(null).getPath();

祝你拥有愉快的一天和愉快的编码 无法在Android 11上以编程方式拍照 – 意图返回已取消状态。

英文:

you shouldn't use "getExternalStoragePublicDirectory()" because this is SHARED STORAGE behaviour and from (probably) 5 july 2021 all applications on the Play Store MUST target android SDK 30 and use Scoped Storage only (so you can't use "requestLegacyStorage", idk about "preserveLegacyStorage").

I suggest you to change the destination path to:

context.getExternalFilesDir(null).getPath();

Have a nice Day & a Nice Coding 无法在Android 11上以编程方式拍照 – 意图返回已取消状态。

答案3

得分: 0

这是一种奇怪的行为,但如果你使用MediaStore.EXTRA_OUTPUT标志的方法,在*onActivityResult()*中始终会返回空数据,并且你需要在你指定的位置查找你的数据:

CurrentUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + &quot;.provider&quot;, CurrentFile);

因此,有两种不同的处理结果的方法。

英文:

This is a strange behaviour but if you use MediaStore.EXTRA_OUTPUT flag method onActivityResult() will always return null data and you are expected to look for your data at location you pointed out here:

CurrentUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + &quot;.provider&quot;, CurrentFile);

So there are two different ways of handling result you are looking for

huangapple
  • 本文由 发表于 2020年10月12日 23:43:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/64321017.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定