Почему я не могу получить доступ к камере в приложении Android Instant?

Я пытаюсь разработать мгновенное приложение камеры, но оно всегда выдает сбой, когда я открываю камеру manager.openCamera(cameraId, mStateCallback, null);:

09-10 21:00:55.333 9472-9472/com.pixelslab.stickerpe I/CameraManager: Using legacy camera HAL.
09-10 21:00:55.340 1402-1914/? I/CameraService: CameraService::connect call (PID -1 "com.pixelslab.stickerpe", camera ID 0) for HAL version default and Camera API version 1
09-10 21:00:55.340 1402-1914/? W/ServiceManager: Permission failure: android.permission.CAMERA from uid=10088 pid=9472
09-10 21:00:55.340 1402-1914/? E/CameraService: Permission Denial: can't use the camera pid=9472, uid=10088
09-10 21:00:55.345 9472-9472/com.pixelslab.stickerpe D/AndroidRuntime: Shutting down VM
09-10 21:00:55.348 9472-9472/com.pixelslab.stickerpe E/AndroidRuntime: FATAL EXCEPTION: 
     main Process: com.pixelslab.stickerpe, PID: 9472
     java.lang.SecurityException: Lacking privileges to access camera service
     at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:643)
     at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:340)
     at android.hardware.camera2.CameraManager.openCameraForUid(CameraManager.java:466)
     at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:430)
     at com.gomo.minivideo.camera2.Camera2VideoFragment.openCamera(Camera2VideoFragment.java:378)
     at com.gomo.minivideo.camera2.Camera2VideoFragment.access$000(Camera2VideoFragment.java:65)
     at com.gomo.minivideo.camera2.Camera2VideoFragment$1.onSurfaceTextureAvailable(Camera2VideoFragment.java:120)
     at android.view.TextureView.getHardwareLayer(TextureView.java:390)
     at android.view.TextureView.draw(TextureView.java:339)
     at android.view.View.updateDisplayListIfDirty(View.java:18069)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.updateDisplayListIfDirty(View.java:18060)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.updateDisplayListIfDirty(View.java:18060)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.updateDisplayListIfDirty(View.java:18060)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.updateDisplayListIfDirty(View.java:18060)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.updateDisplayListIfDirty(View.java:18060)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.updateDisplayListIfDirty(View.java:18060)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.updateDisplayListIfDirty(View.java:18060)
     at android.view.View.draw(View.java:18847)
     at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
     at android.view.View.draw(View.java:19122)
     at com.android.internal.policy.DecorView.draw(DecorView.java:785)
     at android.view.View.updateDisplayListIfDirty(View.java:18069)
     at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:643)
     at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:649)
     at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:757)
     at android.view.ViewRootImpl.draw(ViewRootImpl.java:2980)
     at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2794)
     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2347)
     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386)
     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733)
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
     at android.view.Choreographer.doCallbacks(Choreographer.java:723)
     at android.view.Choreographer.doFrame(Choreographer.java:658)
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
     at android.os.Handler.handleCallback(Handler.java:789)
     at android.os.Handler.dispatchMessage(Handler.java:98)
     at android.os.Looper.loop(Looper.java:164)
     at android.app.ActivityThread.main(ActivityThread.java:6541)
09-10 21:00:55.349 9472-9472/com.pixelslab.stickerpe E/AndroidRuntime:
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
       Caused by: android.os.ServiceSpecificException: Lacking privileges to access camera service (code 1)
     at android.hardware.camera2.legacy.LegacyExceptionUtils.throwOnServiceError(LegacyExceptionUtils.java:132)
     at android.hardware.camera2.legacy.CameraDeviceUserShim.connectBinderShim(CameraDeviceUserShim.java:374)
     at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:317)
     ... 61 more

Однако я уверен, что у меня есть разрешение на камеру, потому что тот же код успешно работает в установленной версии.

Кто-нибудь может это решить? Благодарю вас!

Вот код потерпел крах:

// CameraFragment.java
private TextureView.SurfaceTextureListener mSurfaceTextureListener
        = new TextureView.SurfaceTextureListener() {

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
                                          int width, int height) {
        openCamera(width, height);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
                                            int width, int height) {
        configureTransform(width, height);
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
    }

};

private void openCamera(int width, int height) {
    final Activity activity = getActivity();
    if (null == activity || activity.isFinishing()) {
        return;
    }
    CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
    try {
        Log.d(TAG, "tryAcquire");
        if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
            throw new RuntimeException("Time out waiting to lock camera opening.");
        }
        String cameraId = manager.getCameraIdList()[0];

        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
        StreamConfigurationMap map = characteristics
                .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        if (map == null) {
            throw new RuntimeException("Cannot get available preview/video sizes");
        }
        mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
        mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                width, height, mVideoSize);

        int orientation = getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        } else {
            mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
        }
        configureTransform(width, height);
        mMediaRecorder = new MediaRecorder();
        manager.openCamera(cameraId, mStateCallback, null); // here will crash!!!
    } catch (CameraAccessException e) {
        Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
        activity.finish();
    } catch (NullPointerException e) {
        ErrorDialog.newInstance(getString(R.string.camera_error))
                .show(getChildFragmentManager(), FRAGMENT_DIALOG);
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted while trying to lock camera opening.");
    }
}

И вот как я получаю разрешение камеры:

// MainActivity.java
private void requestCameraPermission() {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.CAMERA)) {
        Snackbar.make(mRootView, R.string.permission_camera_rationale,
                Snackbar.LENGTH_INDEFINITE)
                .setAction(R.string.ok, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, REQUEST_CAMERA);
                    }
                })
                .show();
    } else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA,
                Manifest.permission.INTERNET, Manifest.permission.RECORD_AUDIO}, REQUEST_CAMERA);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CAMERA) {
        if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            getSupportFragmentManager().beginTransaction().replace(R.id.content_layout, Camera2VideoFragment.newInstance()).commitAllowingStateLoss();
            //getSupportFragmentManager().beginTransaction().replace(R.id.content_layout, new CameraFragment()).commitAllowingStateLoss();
        }
    }
}

И вот мой полный файл манифеста:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.pixelslab.stickerpe">

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true"
        android:xlargeScreens="true" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.RECORD_VIDEO" />
    <uses-permission android:name="android.permission.CAMERA" />

    <application
        android:name="com.gomo.minivideo.CameraApp"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/CameraTheme">
        <activity
            android:name="com.gomo.minivideo.MainActivity"
            android:configChanges="orientation|screenSize|keyboardHidden"
            android:launchMode="singleTop"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data
                android:name="default-url"
                android:value="https://hugo775128583.github.io/main" />

            <intent-filter android:order="1" android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:scheme="https"
                    android:host="hugo775128583.github.io"
                    android:pathPrefix="/main" />
            </intent-filter>
            <intent-filter android:order="1" android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:scheme="http"
                    android:host="hugo775128583.github.io"
                    android:pathPrefix="/main" />
            </intent-filter>
        </activity>

        <service android:name="com.jb.zcamera.camera.ProcessVideoService" />

        <activity android:name="com.gomo.minivideo.camera.ShareActivity" />
        <activity android:name="com.gomo.minivideo.camera.VideoViewActivity" />
    </application>

</manifest>

comment
Нам тоже нужен код, пожалуйста! Не могу сказать, что происходит без кода.   -  person chrips    schedule 10.09.2017
comment
Спасибо за предложения. И я только что выложил код.   -  person JavenRuan    schedule 10.09.2017
comment
@JavenRuan Итак, диалоговое окно запроса разрешения появляется в вашем мгновенном приложении, и после того, как вы предоставляете разрешение камеры, фрагмент пытается открыть камеру и падает, за исключением выше. Это правильно? Не могли бы вы также опубликовать свой файл манифеста?   -  person Idolon    schedule 11.09.2017
comment
@Idolon, Да, ты совершенно прав! И я разместил свой файл манифеста, пожалуйста, проверьте.   -  person JavenRuan    schedule 11.09.2017
comment
@JavenRuan Нет такого понятия, как разрешение android.permission.RECORD_VIDEO. Вероятно, это не источник вашей проблемы, но вы можете безопасно удалить его из манифеста.   -  person Idolon    schedule 11.09.2017
comment
@JavenRuan Можете ли вы опубликовать zip-файл с мгновенным приложением? Когда я запускаю Instant App с кодом, похожим на ваш, и все работает нормально.   -  person Idolon    schedule 14.09.2017
comment
@JavenRuan, на каком устройстве вы тестируете и какая версия Android на нем работает? Вы можете увидеть, происходит ли это на других устройствах или эмуляторах? Похоже на глюк конкретного устройства. Было бы очень полезно, если бы вы сообщили об ошибке на странице issuetracker.google.com/issues? q=componentid:316045 (и если вы можете показать, что это зависит от устройства, это тоже поможет).   -  person philo    schedule 14.09.2017
comment
@Idolon Я использую Samsung s7 (Android 7.0), и все работает нормально. Но сбой в этом посте только что произошел на Android 8.0, таком как Nexus 6p или эмуляторах.   -  person JavenRuan    schedule 19.09.2017
comment
@philo, да, я обнаружил, что только Android 7.0 может идеально запускать мой код, например Samsung s7.   -  person JavenRuan    schedule 19.09.2017
comment
@JavenRuan, можете ли вы где-нибудь опубликовать APK-файл Instant App, чтобы я мог протестировать его на других устройствах с Android 8.0?   -  person Idolon    schedule 19.09.2017
comment
@JavenRuan, пожалуйста, сообщите об ошибке по адресу issuetracker.google.com/issues?q=componentid:316045. Мы можем направить это непосредственно ответственной команде.   -  person philo    schedule 20.09.2017
comment
@Idolon Спасибо, вы можете проверить этот репозиторий github.com/FlareMars/MiniVideo-Instant , и запустить его самостоятельно. Это пример проекта, не жалуйтесь на ужасный код :)   -  person JavenRuan    schedule 20.09.2017


Ответы (3)


Это выглядит как ошибка, воспроизводимая на Android O. Ее также можно воспроизвести с помощью примера проекта Camera2Basic, адаптированного для приложения с мгновенным запуском:
https://github.com/Idolon-V/InstantApp-Камера

Я зарегистрировал ошибку в трекере Google: https://issuetracker.google.com/issues/66942980

person Idolon    schedule 26.09.2017

добавьте эту строку в файл манифеста

<uses-feature android:name="android.hardware.camera"></uses-feature>
person Shiva Kanumala    schedule 27.09.2017

Со ссылкой на систему отслеживания ошибок Google,

Эта проблема была исправлена ​​и развернута на устройствах 8.1. Мы работаем с нашими партнерами, чтобы внедрить исправление в обновление для устройств 8.0. Мы ожидаем, что эти обновления будут выпущены в ближайшие месяцы.

Если какая-либо проблема не устранена, сообщите об этом в системе отслеживания проблем Google, и они снова откроются для проверки.

person Prags    schedule 13.12.2017