Новые URI KitKat не отвечают на Intent.ACTION_VIEW

Так как KitKat изменил URI от сборщиков до уровня

 content://com.android.providers.media.documents/document/image:3951

то ни один из моих действий ACTION_VIEW больше не работает. Когда, например, пользователь выбирает изображение, я использую

public static void openImage(Fragment f, Uri uri) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(uri, "image/*");

        f.startActivity(intent);
    }

а также Галерея Android и Google+ Фото, но когда выбрано, Галерея просто показывает пустые экраны, в Фото сказано, что "medium not found"

То же самое со звуками, я использую

public static void playSound(Fragment f, Uri uri) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(uri, "audio/*");

    f.startActivity(intent);
}

который использовался для показа Google Play Музыки в предыдущих версиях, с небольшим пользовательским интерфейсом белого воспроизведения. С новыми URI я получаю исключение, что ни одно приложение не может справиться с этим намерением.

//С фотографиями смешно, что при выборе "Галерея" вместо "Картинки" в новом пользовательском интерфейсе KK picker он возвращает старые URI, которые работают.

Любые идеи? Являются ли системные приложения просто не готовыми к новому урису? Должен ли я каким-то образом взломать новый уристать старым, чтобы они работали? Или я что-то упускаю?

Спасибо!

Ответ 1

Решение состоит в том, чтобы передать флаг FLAG_GRANT_READ_URI_PERMISSION в намерение (на KitKat и выше):

intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Также убедитесь, что это содержимое Uri было извлечено из намерения ACTION_OPEN_DOCUMENT, как описано здесь: fooobar.com/questions/12209/...

Ответ 2

Вы можете использовать следующее намерение, чтобы выбрать изображение из галереи

Intent i = new Intent (Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, 2);

и получить выбранное изображение в onActivityResult, например,

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    if(data==null)return;

    try {
      Bitmap bit = scaleImage(this, data.getData());
      img.setImageBitmap(bit);
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static Bitmap scaleImage(Context context, Uri photoUri) throws IOException {
        InputStream is = context.getContentResolver().openInputStream(photoUri);

        BitmapFactory.Options dbo = new BitmapFactory.Options();

        dbo.inJustDecodeBounds = true;

        BitmapFactory.decodeStream(is, null, dbo);

        is.close();

        int rotatedWidth, rotatedHeight;
        int orientation = getOrientation(context, photoUri);

        if (orientation == 90 || orientation == 270) {
            rotatedWidth = dbo.outHeight;
            rotatedHeight = dbo.outWidth;
        } else {
            rotatedWidth = dbo.outWidth;
            rotatedHeight = dbo.outHeight;
        }

        Bitmap srcBitmap;
        is = context.getContentResolver().openInputStream(photoUri);
        if (rotatedWidth > 100 || rotatedHeight > 100) {
            float widthRatio = ((float) rotatedWidth) / ((float) 100);
            float heightRatio = ((float) rotatedHeight) / ((float) 100);
            float maxRatio = Math.max(widthRatio, heightRatio);

            // Create the bitmap from file
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = (int) maxRatio;
            srcBitmap = BitmapFactory.decodeStream(is, null, options);
        } else {
            srcBitmap = BitmapFactory.decodeStream(is);
        }
        is.close();

        /*
         * if the orientation is not 0 (or -1, which means we don't know), we
         * have to do a rotation.
         */
        if (orientation > 0) {
            Matrix matrix = new Matrix();
            matrix.postRotate(orientation);

            srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                    srcBitmap.getHeight(), matrix, true);
        }

        String type = context.getContentResolver().getType(photoUri);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        if (type.equals("image/png")) {
            srcBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
        } else if (type.equals("image/jpg") || type.equals("image/jpeg")) {
            srcBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        }
        byte[] bMapArray = baos.toByteArray();
        baos.close();
        return BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length);
    }

    public static int getOrientation(Context context, Uri photoUri) {
        /* it on the external media. */
        Cursor cursor = context.getContentResolver().query(photoUri,
                new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

        if (cursor.getCount() != 1) {
            return -1;
        }

        cursor.moveToFirst();
        return cursor.getInt(0);
    }