I am using Camera2API in Android 6.0. I was done without error in Android 5.0. However, when I used my code in the Android 6.0, I have a issue. The issue is that sometime I can open the camera successfully and take picture. However, sometime the camera cannot open and it has error
java.lang.SecurityException: Lacking privileges to access camera service at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:108)
I added the runtime permission as follows:
String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA}; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if(!hasAllPermissions(this, PERMISSIONS)){ ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL); } } public static boolean hasAllPermissions(Context context, String... permissions) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) { for (String permission : permissions) { if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } } return true; }
This is all log
FATAL EXCEPTION: main Process: com.example.camera2api, PID: 5376 java.lang.SecurityException: Lacking privileges to access camera service at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:108) at android.hardware.camera2.utils.CameraBinderDecorator$CameraBinderDecoratorListener.onAfterInvocation(CameraBinderDecorator.java:73) at android.hardware.camera2.utils.Decorator.invoke(Decorator.java:81) at java.lang.reflect.Proxy.invoke(Proxy.java:393) at $Proxy2.cancelRequest(Unknown Source) at android.hardware.camera2.impl.CameraDeviceImpl.stopRepeating(CameraDeviceImpl.java:926) at android.hardware.camera2.impl.CameraCaptureSessionImpl.close(CameraCaptureSessionImpl.java:378) at android.hardware.camera2.impl.CameraCaptureSessionImpl$2.onDisconnected(CameraCaptureSessionImpl.java:514) at android.hardware.camera2.impl.CameraDeviceImpl$7.run(CameraDeviceImpl.java:228) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:158) at android.app.ActivityThread.main(ActivityThread.java:7229) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
update: For someone who want to look at my full code. I upload my full code here
public class AndroidCamera extends AppCompatActivity {
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } private static final String TAG = "Camera2App"; private String mImageFileLocation = ""; private static final int STATE_PREVIEW = 0; private static final int STATE_WAIT_LOCK = 1; private static final int STATE_WAITING_PRECAPTURE = 2; /** * Camera state: Waiting for the exposure state to be something other than precapture. */ private static final int STATE_WAITING_NON_PRECAPTURE = 3; /** * Camera state: Picture was taken. */ private static final int STATE_PICTURE_TAKEN = 4; private int mState; private TextureView mTextureView; private Size mPreviewSize; private String mCameraId; String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA}; private static final int PERMISSION_ALL = 105; private static final int REQUEST_CAMERA_RESULT = 106; private boolean isRegistred=false; private int mSensorOrientation; private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { if (!TextUtils.isEmpty(BleUtils.getCameraLens(AndroidCamera.this))) setupCamera(width, height,BleUtils.getCameraLens(AndroidCamera.this)); else setupCamera(width, height,"1"); openCamera(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { //closeCamera(); return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } }; private Semaphore mCameraOpenCloseLock = new Semaphore(1); private CameraDevice mCameraDevice; private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraOpenCloseLock.release(); mCameraDevice = camera; //Toast.makeText(getApplicationContext(),"Camera Opened!", Toast.LENGTH_SHORT).show(); createCameraPreviewSession(); } @Override public void onDisconnected(CameraDevice camera) { camera.close(); mCameraDevice = null; } @Override public void onError(CameraDevice camera, int error) { camera.close(); mCameraDevice = null; } }; private CaptureRequest mPreviewCaptureRequest; private CaptureRequest.Builder mPreviewCaptureRequestBuilder; private CameraCaptureSession mCameraCaptureSession; private CameraCaptureSession.CaptureCallback mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() { private void process(CaptureResult result){ switch (mState){ case STATE_PREVIEW: break; case STATE_WAIT_LOCK: Integer afState=result.get(CaptureResult.CONTROL_AF_STATE); if(afState==CaptureRequest.CONTROL_AF_STATE_FOCUSED_LOCKED){ captureStillImage(); } else{ captureStillImage(); } break; } } @Override public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) { super.onCaptureStarted(session, request, timestamp, frameNumber); } @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); process(result); } @Override public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) { super.onCaptureFailed(session, request, failure); Handler mHandler = new Handler(getMainLooper()); mHandler.post(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "Focus Lock UnSuccesful", Toast.LENGTH_SHORT).show(); } }); } }; private HandlerThread mBackgroundThread; private Handler mBackgroundHandler; private static File mImageFile; private ImageReader mImageReader; private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage())); } }; private static class ImageSaver implements Runnable { private final Image mImage; private ImageSaver(Image image) { mImage = image; } @Override public void run() { ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer(); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(mImageFile); fileOutputStream.write(bytes); } catch (IOException e) { e.printStackTrace(); } finally { mImage.close(); if (fileOutputStream != null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera_activity); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if(!hasAllPermissions(this, PERMISSIONS)){ ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL); } } mTextureView = (TextureView) findViewById(R.id.texture); } public static boolean hasAllPermissions(Context context, String... permissions) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) { for (String permission : permissions) { if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } } return true; } @Override public void onStart() { super.onStart(); if (!EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().register(this); } } //onStop @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } @Subscribe public void onCaptureNumberReceived(OnCaptureEvent event) { //get the phone number value here and do something with it String capturecode = event.getCodeCapture(); Log.d(TAG, capturecode); if (capturecode.equals("capture")) { try { mImageFile = createImageFile(); } catch (IOException e) { e.printStackTrace(); } lockFocus(); MediaActionSound sound = new MediaActionSound(); sound.play(MediaActionSound.SHUTTER_CLICK); } else if(capturecode.equals("end_capture")) { finish(); // call this to finish the current activity Intent homeIntent = new Intent(Intent.ACTION_MAIN); homeIntent.addCategory( Intent.CATEGORY_HOME ); homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(homeIntent); } } public void takepicture(View view) { try { mImageFile = createImageFile(); Log.d("TAG","=====Take picture====="); } catch (IOException e) { e.printStackTrace(); } lockFocus(); MediaActionSound sound = new MediaActionSound(); sound.play(MediaActionSound.SHUTTER_CLICK); } public void switch_camera(View view) { closeCamera(); //swap the id of the camera to be used if(mCameraId == String.valueOf(Camera.CameraInfo.CAMERA_FACING_BACK)){ mCameraId = String.valueOf(Camera.CameraInfo.CAMERA_FACING_FRONT); } else { mCameraId = String.valueOf(Camera.CameraInfo.CAMERA_FACING_BACK); } BleUtils.setCameraLens(this, mCameraId); if (mTextureView.isAvailable()) { setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),mCameraId); openCamera(); } else { mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); } } File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "BLE_" + timeStamp + "_"; File storageDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); if(!storageDirectory.exists()){ if(!storageDirectory.mkdirs()){ Log.e("Dir", "Failed to create directory"); Log.d("MAKE DIR", storageDirectory.mkdir() + "" + storageDirectory.getParentFile() + ""); return null; } } File image = File.createTempFile(imageFileName, ".jpg", storageDirectory); mImageFileLocation = image.getAbsolutePath(); return image; } @Override public void onResume() { super.onResume(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if(!hasAllPermissions(this, PERMISSIONS)){ ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL); } } openBackgroundThread(); if (mTextureView.isAvailable()) { if (!TextUtils.isEmpty(BleUtils.getCameraLens(AndroidCamera.this))) setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),BleUtils.getCameraLens(AndroidCamera.this)); else setupCamera(mTextureView.getWidth(), mTextureView.getHeight(),"1"); closeCamera(); openCamera(); } else { mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); } } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG,"onDestroy"); } public void onPause() { Log.d(TAG,"onPause"); closeCamera(); closeBackgroundThread(); super.onPause(); } private void setupCamera(int width, int height, String cameraId) { CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId); StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size largestImageSize = Collections.max( Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new Comparator<Size>() { @Override public int compare(Size lhs, Size rhs) { return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight()); } } ); mImageReader = ImageReader.newInstance(largestImageSize.getWidth(), largestImageSize.getHeight(), ImageFormat.JPEG, 1); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); mPreviewSize = getPreferredPreviewSize(map.getOutputSizes(SurfaceTexture.class), width, height); mCameraId = cameraId; Log.d("CAMERA_ID",String.valueOf(mCameraId)); // } } catch (CameraAccessException e) { e.printStackTrace(); } } private Size getPreferredPreviewSize(Size[] mapSizes, int width, int height) { List<Size> collectorSizes = new ArrayList<>(); for (Size option : mapSizes) { if (width > height) { if (option.getWidth() > width && option.getHeight() > height) { collectorSizes.add(option); } } else { if (option.getWidth() > height && option.getHeight() > width) { collectorSizes.add(option); } } } if (collectorSizes.size() > 0) { return Collections.min(collectorSizes, new Comparator<Size>() { @Override public int compare(Size lhs, Size rhs) { return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight()); } }); } return mapSizes[0]; } private void openCamera() { CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { Log.v("CAMERA", mCameraId + " " + mCameraDeviceStateCallback); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){ cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback,mBackgroundHandler); } else { if (shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA)){ Toast.makeText(this,"No Permission to use the Camera services", Toast.LENGTH_SHORT).show(); } requestPermissions(new String[] {android.Manifest.permission.CAMERA},REQUEST_CAMERA_RESULT); } } else { cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler); } } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode){ case REQUEST_CAMERA_RESULT: if (grantResults[0] != PackageManager.PERMISSION_GRANTED){ Toast.makeText(this, "Cannot run application because camera service permission have not been granted", Toast.LENGTH_SHORT).show(); } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); break; } } private void closeCamera(){ if(mCameraCaptureSession!=null){ mCameraCaptureSession.close(); mCameraCaptureSession=null; } if (mCameraDevice!=null){ mCameraDevice.close(); mCameraDevice=null; if(mImageReader!=null){ mImageReader.close(); mImageReader=null; } } } private void createCameraPreviewSession(){ try{ SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight()); Surface previewSurface= new Surface(surfaceTexture); mPreviewCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewCaptureRequestBuilder.addTarget(previewSurface); mPreviewCaptureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte)100); mCameraDevice.createCaptureSession(Arrays.asList(previewSurface,mImageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { if(mCameraDevice==null){ return; } try { mPreviewCaptureRequest = mPreviewCaptureRequestBuilder.build(); mCameraCaptureSession = session; mCameraCaptureSession.setRepeatingRequest( mPreviewCaptureRequest, mSessionCaptureCallback, mBackgroundHandler ); }catch (CameraAccessException e){ e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { Handler mHandler = new Handler(getMainLooper()); mHandler.post(new Runnable() { @Override public void run() { Toast.makeText( getApplicationContext(), "create camera session failed!", Toast.LENGTH_SHORT ).show(); } }); } },null); }catch (CameraAccessException e){ e.printStackTrace(); } } private void openBackgroundThread(){ mBackgroundThread=new HandlerThread("Camera2 background thread"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); } private void closeBackgroundThread(){ mBackgroundThread.quitSafely(); try{ mBackgroundThread.join(); mBackgroundThread=null; mBackgroundHandler=null; }catch (InterruptedException e){ e.printStackTrace(); } } private void lockFocus(){ try{ mState=STATE_WAIT_LOCK; mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); mCameraCaptureSession.capture(mPreviewCaptureRequestBuilder.build(), mSessionCaptureCallback,mBackgroundHandler); }catch (CameraAccessException e){ e.printStackTrace(); } } private void unLockFocus(){ try{ mState=STATE_PREVIEW; mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); mCameraCaptureSession.capture(mPreviewCaptureRequestBuilder.build(), mSessionCaptureCallback,mBackgroundHandler); }catch (CameraAccessException e){ e.printStackTrace(); } } private void captureStillImage(){ try { CaptureRequest.Builder captureStillBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureStillBuilder.addTarget(mImageReader.getSurface()); // Use the same AE and AF modes as the preview. captureStillBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // setAutoFlash(captureBuilder); // Orientation int rotation=0; //Front camera if(mCameraId.equals("1")) { rotation = this.getWindowManager().getDefaultDisplay().getRotation(); captureStillBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation)); } else { rotation = this.getWindowManager().getDefaultDisplay().getRotation(); captureStillBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); } CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); //Toast.makeText(getApplicationContext(),"Image Captured",Toast.LENGTH_SHORT).show(); unLockFocus(); } }; mCameraCaptureSession.capture( captureStillBuilder.build(),captureCallback,null ); }catch (CameraAccessException e){ e.printStackTrace(); } } private int getOrientation(int rotation) { return (ORIENTATIONS.get(rotation) + mSensorOrientation +180) % 360; }
}