java.lang.illegalaccessexception:尝试从非可视上下文访问可视服务windowmanager

8dtrkrch  于 2021-06-29  发布在  Java
关注(0)|答案(0)|浏览(1566)

我一直努力在我的应用程序中实现摄像头功能,但不会产生以下错误:
e/contextimpl:尝试从非可视窗口访问可视服务windowmanagercontext:com.camtest.app@385f002 可视服务,如windowmanager、WallperService或LayoutFlater,应该从活动或其他可视上下文访问。使用使用context#createwindowcontext(int,bundle)创建的活动或上下文,这些活动或上下文会根据屏幕上某个区域的配置和可视边界进行调整。java.lang.illegalaccessexception:尝试从非可视窗口访问可视服务windowmanagercontext:com.camtest.app@385f002
该错误由以下行触发:

final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

我看着他 createWindowContext 正如这个错误所暗示的,但是一些目标设备比较旧,不能升级到android 11,因此 createWindowContext 不是一个选择。
第一次,我跟随一个代码实验室来实现camerax。摄影机的行为与预期一致,但触发了异常。所以我找到了一个不同的实现camerax的例子,但是我得到了相同的结果 IllegalAccessException 例外。
有什么建议吗?

package com.camtest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import com.google.common.util.concurrent.ListenableFuture;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class CamTest extends AppCompatActivity {

    private Executor executor = Executors.newSingleThreadExecutor();
    private int REQUEST_CODE_PERMISSIONS = 9001;
    private final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA", "android.permission.WRITE_EXTERNAL_STORAGE"};

    PreviewView mPreviewView;
    ImageView captureImage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.camera_test);

        mPreviewView = findViewById(R.id.camera);//was previewView
        captureImage = findViewById(R.id.captureImg);

        if(allPermissionsGranted()){
            startCamera(); //start camera if permission has been granted by user
        } else{
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
        }
    }

    private void startCamera() {

        final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); //This line triggers `E/ContextImpl: Tried to access visual service WindowManager from a non-visual Context`

        cameraProviderFuture.addListener(new Runnable() {
            @Override
            public void run() {
                try {

                    ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                    bindPreview(cameraProvider);

                } catch (ExecutionException | InterruptedException e) {
                    // No errors need to be handled for this Future.
                    // This should never be reached.
                }
            }
        }, ContextCompat.getMainExecutor(this));
    }

    void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
        Preview preview = new Preview.Builder().build();

        ImageCapture imageCapture = new ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .build();

        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        Camera camera = cameraProvider.bindToLifecycle(
                ((LifecycleOwner) this),
                cameraSelector,
                preview,
                imageCapture);

        preview.setSurfaceProvider(
                mPreviewView.getSurfaceProvider());

        captureImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
                File file = new File(getBatchDirectoryName(), mDateFormat.format(new Date())+ ".jpg");

                ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
                imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback () {
                    @Override
                    public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                        new Handler().post(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(CamTest.this, "Image Saved successfully", Toast.LENGTH_SHORT).show();
                            }
                        });
                    }
                    @Override
                    public void onError(@NonNull ImageCaptureException error) {
                        error.printStackTrace();
                    }
                });
            }
        });
    }

    public String getBatchDirectoryName() {

        String app_folder_path = "";
        app_folder_path = Environment.getExternalStorageDirectory().toString() + "/images";
        File dir = new File(app_folder_path);
        if (!dir.exists() && !dir.mkdirs()) {

        }

        return app_folder_path;
    }

    private boolean allPermissionsGranted(){

        for(String permission : REQUIRED_PERMISSIONS){
            if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
                return false;
            }
        }
        return true;
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        if(requestCode == REQUEST_CODE_PERMISSIONS){
            if(allPermissionsGranted()){
                startCamera();
            } else{
                Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show();
                this.finish();
            }
        }
    }
}

此活动由以下代码在oncreate of mainactivity中启动:

Button button_test = findViewById(R.id.button_test);
button_test.setOnClickListener(view -> {
     Intent intent = new Intent(MainActivity.this, CamTest.class);
     startActivityForResult(intent,0);
});

编辑:完整堆栈跟踪-

E/ContextImpl: Tried to access visual service WindowManager from a non-visual Context:com.camtest.App@dd90e6b Visual services, such as WindowManager, WallpaperService or LayoutInflater should be accessed from Activity or other visual Context. Use an Activity or a Context created with Context#createWindowContext(int, Bundle), which are adjusted to the configuration and visual bounds of an area on screen.
    java.lang.IllegalAccessException: Tried to access visual service WindowManager from a non-visual Context:com.camtest.App@dd90e6b
        at android.app.ContextImpl.getSystemService(ContextImpl.java:1914)
        at android.content.ContextWrapper.getSystemService(ContextWrapper.java:803)
        at androidx.camera.camera2.internal.Camera2UseCaseConfigFactory.<init>(Camera2UseCaseConfigFactory.java:50)
        at androidx.camera.camera2.Camera2Config.lambda$defaultConfig$1(Camera2Config.java:60)
        at androidx.camera.camera2.-$$Lambda$Camera2Config$g_hY10kZhqC56um0PalOLTzuFlU.newInstance(Unknown Source:0)
        at androidx.camera.core.CameraX.lambda$initAndRetryRecursively$9$CameraX(CameraX.java:575)
        at androidx.camera.core.-$$Lambda$CameraX$u-Xx2b6YXY5GXNXRh-mDiDnHdpQ.run(Unknown Source:10)
        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:923)

编辑#2:要重现此错误,必须启用vmpolicy的strictmode。以下代码已添加到mainactivity.oncreate:

if( BuildConfig.BUILD_TYPE.contentEquals( "debug" ) ){
    /*StrictMode.setThreadPolicy( new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());*/
    StrictMode.setVmPolicy( new StrictMode.VmPolicy.Builder()
            .detectAll()//.detectNonSdkApiUsage()
            .penaltyLog()
            .build());
}

编辑#3:从camerax版本1.0.0-beta12更新到1.0.0-rc1(今天的当前版本)没有效果

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题