Android - невозможно использовать один и тот же URI дважды при выборе изображения - PullRequest
1 голос
/ 18 июня 2019

Я использую библиотеку для обрезки фотографий (версия 2.7 здесь: https://github.com/ArthurHub/Android-Image-Cropper)), чтобы выбрать и обрезать изображение с помощью приложений галереи (таких как галерея Samsung, фотографии Google, файлы и т. Д.). Библиотека работает, запуская намерение выбора с Intent.ACTION_GET_CONTENT, и после того, как пользователь выбирает изображение, Uri передается в представление обрезки, которое открывает растровое изображение. В некоторых ситуациях мне нужно сбросить обрезку, автоматически используя Uri из фотографии, выбранной пользователем в последний раз. Итак, после того, как пользователь выбирает изображение, я запоминаю Uri, затем использую тот же Uri, чтобы начать этап обрезки (который декодирует растровое изображение).

Это работает для галереи Samsung, но у меня есть проблема с Google Photos, которая выдает исключение SecurityException при повторном открытии URI. Таким образом, выбор изображения с фотографиями Google работает правильно в первый раз, когда пользователь выбирает только изображение. Когда я пытаюсь передать тот же Uri (когда я сбрасываю обрезку), я получаю исключение ниже (это также происходит с «Files» - я тестировал на эмуляторе и Motorola один):

java.lang.RuntimeException: Failed to load sampled bitmap: content://com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2Flocal%253Ace62f6ca-6054-486b-bbb1-b6145ac50272/ORIGINAL/NONE/27402515
    Permission Denial: opening provider com.google.android.apps.photos.contentprovider.impl.MediaContentProvider from ProcessRecord{82bb7a9 12497:app.myapp/u0a188} (pid=12497, uid=10188) that is not exported from UID 10093
        at com.theartofdev.edmodo.cropper.BitmapUtils.decodeSampledBitmap(BitmapUtils.java:130)
        at com.theartofdev.edmodo.cropper.BitmapLoadingWorkerTask.doInBackground(BitmapLoadingWorkerTask.java:73)
        at com.theartofdev.edmodo.cropper.BitmapLoadingWorkerTask.doInBackground(BitmapLoadingWorkerTask.java:24)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.contentprovider.impl.MediaContentProvider from ProcessRecord{82bb7a9 12497:app.myapp/u0a188} (pid=12497, uid=10188) that is not exported from UID 10093
        at android.os.Parcel.createException(Parcel.java:1950)
        at android.os.Parcel.readException(Parcel.java:1918)
        at android.os.Parcel.readException(Parcel.java:1868)
        at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:4118)

Код, используемый для отображения пользователю, из какого приложения выбрать фотографию:

List<Intent> allIntents = new ArrayList<>();
PackageManager packageManager = this.getPackageManager();

boolean includeCamera = useCamera;
// collect all camera intents if Camera permission is available
if (!CropImage.isExplicitCameraPermissionRequired(this) && includeCamera) {
    allIntents.addAll(CropImage.getCameraIntents(this, packageManager));
}

boolean includeDocuments = false;
if (useGallery) {
    List<Intent> galleryIntents =
            CropImage.getGalleryIntents(packageManager, Intent.ACTION_GET_CONTENT, includeDocuments);
    if (galleryIntents.size() == 0) {
        // if no intents found for get-content try pick intent action (Huawei P9).
        galleryIntents = CropImage.getGalleryIntents(packageManager, Intent.ACTION_PICK, includeDocuments);
    }
    allIntents.addAll(galleryIntents);
}

Intent target;
if (allIntents.isEmpty()) {
    target = new Intent();
} else {
    target = allIntents.get(allIntents.size() - 1);
    allIntents.remove(allIntents.size() - 1);
}

// Create a chooser from the main  intent
Intent chooserIntent = Intent.createChooser(target, "Choose");

// Add all other intents
chooserIntent.putExtra(
        Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));

this.startActivityForResult(
        chooserIntent
        , CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE);

И метод CropImage.getGalleryIntents:

  public static List<Intent> getGalleryIntents(
      @NonNull PackageManager packageManager, String action, boolean includeDocuments) {
    List<Intent> intents = new ArrayList<>();
    Intent galleryIntent =
        action == Intent.ACTION_GET_CONTENT
            ? new Intent(action)
            : new Intent(action, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    galleryIntent.setType("image/*");
    List<ResolveInfo> listGallery = packageManager.queryIntentActivities(galleryIntent, 0);
    for (ResolveInfo res : listGallery) {
      Intent intent = new Intent(galleryIntent);
      intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
      intent.setPackage(res.activityInfo.packageName);
      intents.add(intent);
    }

    // remove documents intent
    if (!includeDocuments) {
      for (Intent intent : intents) {
        if (intent
            .getComponent()
            .getClassName()
            .equals("com.android.documentsui.DocumentsActivity")) {
          intents.remove(intent);
          break;
        }
      }
    }
    return intents;
  }

У меня есть правильное решение или обходной путь для этого? Спасибо.

1 Ответ

1 голос
/ 18 июня 2019

Используйте ACTION_OPEN_DOCUMENT для вашего galleryIntent.

Но учтите, что даже ACTION_OPEN_DOCUMENT все равно будет признан недействительным через несколько часов.

Единственный способ получить неограниченный доступ к изображению - это сохранить его в собственном хранилище приложения и получить к нему доступ для дальнейшего использования.

...