模拟相机意图结果时出现FileNotFoundException

时间:2019-01-15 23:46:34

标签: android android-espresso android-testing filenotfoundexception android-camera-intent

我正在尝试改进可触发相机应用程序的集成测试。但是,我拦截了这个意图,并且想在集成测试中使用虚拟图像。

因此,我在测试中(相关部分)有以下代码:

@Test
public void runCameraTest() {
//...
IntentCallback intentCallback = intent -> {
            if (intent.getAction() != null && intent.getAction().equals("android.media.action.IMAGE_CAPTURE")) {
                try {
                    Uri imageUri = intent.getParcelableExtra(MediaStore.EXTRA_OUTPUT);
                    Log.d(TAG, "runCameraTest: imageUri: "+imageUri);
                    Context context = InstrumentationRegistry.getTargetContext();
                    Bitmap icon = BitmapFactory.decodeResource(
                            context.getResources(),
                            R.drawable.example_photo);
                    OutputStream out = InstrumentationRegistry.getTargetContext().getContentResolver().openOutputStream(imageUri);
                    icon.compress(Bitmap.CompressFormat.JPEG, 100, out);
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    Log.e(TAG,"runCameraTest-Exception: " + e.getMessage(),e);
                }
            }
        };

        IntentMonitorRegistry.getInstance().addIntentCallback(intentCallback);

        Intents.intending(IntentMatchers.hasAction(MediaStore.ACTION_IMAGE_CAPTURE)).respondWith(
                new Instrumentation.ActivityResult(Activity.RESULT_OK, null));

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        cameraView.perform(click());

        Intents.release();

        Intents.init();
//...
}

然后使用以下方法构建相机意图(不确定是否需要所有SDK if语句,这是由另一位开发人员编写的):

private Intent getCameraIntent() {
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

            try {
                mTempImageFile = File.createTempFile(
                        TEMP_CAMERA_IMAGE_FILE_NAME,  /* prefix */
                        "." + TEMP_CAMERA_IMAGE_FILE_EXT,         /* suffix */
                        getCurrentContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)      /* directory */
                );
            } catch (IOException ex) {
                // Error occurred while creating the File
                Crashlytics.logException(ex);
            }
            // Continue only if the File was successfully created
            if (mTempImageFile != null) {
                mTempImageUri = FileProvider.getUriForFile(getCurrentContext(),
                        getCurrentContext().getString(R.string.content_provider),
                        mTempImageFile);
            }

        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            ContentValues values = new ContentValues(1);
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
            mTempImageUri = getCurrentContext().getContentResolver()
                    .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        } else {
            File outputFile = new File(getStoragePath()
                    + File.separator + TEMP_CAMERA_IMAGE_FILE);

            mTempImageUri = Uri.fromFile(outputFile);
        }

        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mTempImageUri);
        return cameraIntent;
    }

我正在Amazon Device Farm中运行此测试,并且该测试适用于某些设备(Android 7、8和9),但在Samsung Galaxy S6(Android 6.0.1)和Samsung Galaxy Tab 4(Android 4.4.2)中失败)。

错误是在java.io.FileNotFoundException: No such file or directory行上引发了OutputStream out = InstrumentationRegistry.getTargetContext().getContentResolver().openOutputStream(imageUri);

日志显示imageUricontent://media/external/images/media/8244

有人对可能的问题有想法吗?可能与该设备没有SD卡有关吗? (不确定是否是这种情况)

1 个答案:

答案 0 :(得分:0)

> = API级别N,您通常必须使用FileProvider来解析Uri

Uri uri = FileProvider.getUriForFile(context, "com.acme.fileprovider", outputFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

当<= API级别M失败时,这意味着elseifelse分支无法解析Uri

在本地仿真器上进行调试可能有助于确定为什么它无法远程运行。