我想对红米K60的后面两个摄像头同时拍照,但是我不能触发超广角摄像头的
mOnImageAvailableListener2
代码如下
/*
* Copyright 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*d
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.myapplicationnew3;
import java.util.Date;
import android.hardware.camera2.CameraMetadata;
import android.content.Context;
import android.content.Intent;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import androidx.annotation.NonNull;
import android.os.Environment;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.core.content.ContextCompat;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@RequiresApi(api = Build.VERSION_CODES.P)
public class Camera2BasicFragment extends Fragment
implements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {
public static final String TAG = "Camera2BasicFragment";
int flag =0 ;
private class DualCamera{
String logicalId;
String physicalId1;
String physicalId2;
public DualCamera(String s, String s1, String s2) {
logicalId = s;
physicalId1 = s1;
physicalId2 = s2;
}
}
/**
* Conversion from screen rotation to JPEG orientation.
*/
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int REQUEST_CAMERA_PERMISSION = 1;
private static final String FRAGMENT_DIALOG = "dialog";
private int idx=0;
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);
}
/**
* Tag for the {@link Log}.
*/
/**
* Camera state: Showing camera preview.
*/
private static final int STATE_PREVIEW = 0;
/**
* Camera state: Waiting for the focus to be locked.
*/
private static final int STATE_WAITING_LOCK = 1;
/**
* Camera state: Waiting for the exposure to be precapture state.
*/
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;
/**
* Max preview width that is guaranteed by Camera2 API
*/
private static final int MAX_PREVIEW_WIDTH = 1920;
/**
* Max preview height that is guaranteed by Camera2 API
*/
private static final int MAX_PREVIEW_HEIGHT = 1080;
/**
* {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
* {@link TextureView}.
*/
private final TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
};
/**
* ID of the current {@link CameraDevice}.
*/
private String mCameraId;
/**
* An {@link AutoFitTextureView} for camera preview.
*/
private AutoFitTextureView mTextureView;
private AutoFitTextureView mTextureView2;
/**
* A {@link CameraCaptureSession } for camera preview.
*/
private CameraCaptureSession mCaptureSession;
/**
* A reference to the opened {@link CameraDevice}.
*/
private CameraDevice mCameraDevice;
/**
* The {@link Size} of camera preview.
*/
private Size mPreviewSize;
/**
* {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
*/
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
// This method is called when the camera is opened. We start camera preview here.
Log.d(TAG, "startaaa");
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
Activity activity = getActivity();
if (null != activity) {
activity.finish();
}
}
};
/**
* An additional thread for running tasks that shouldn't block the UI.
*/
private HandlerThread mBackgroundThread;
private HandlerThread mBackgroundThread1;
/**
* A {@link Handler} for running tasks in the background.
*/
private Handler mBackgroundHandler;
private Handler mBackgroundHandler1;
/**
* An {@link ImageReader} that handles still image capture. two for both cameras
*/
private ImageReader mImageReader1;
private ImageReader mImageReader2;
/**
* This is the output file for our picture.
*/
private File mFile1;
private File mFile2;
int idx1=0;
int idx2=0;
/**
* This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
* still image is ready to be saved.
*/
//begin
// 修改 mOnImageAvailableListener1 的部分
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener1
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Log.d(TAG, "onImageAvailable for mImageReader1");
idx1 += 1;
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
mFile1 = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM), "R" + String.valueOf(idx1) + timeStamp + ".jpg");
Image image = reader.acquireNextImage();
mBackgroundHandler.post(new ImageSaver(image, mFile1));
// 通知系统将图像添加到相册
galleryAddPic(mFile1.getAbsolutePath());
// image.close();
}
};
// 修改 mOnImageAvailableListener2 的部分
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener2
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Log.d(TAG, "onImageAvailable for mImageReader2");
idx2 += 1;
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
mFile2 = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM), "L" + String.valueOf(idx2) + timeStamp + ".jpg");
// 进行保存图像的逻辑
mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile2));
// 通知系统将图像添加到相册
galleryAddPic(mFile2.getAbsolutePath());
Log.d(TAG, "Image from mImageReader2 saved to " + mFile2.getAbsolutePath());
}
};
// 添加一个方法通知系统将图像添加到相册
private void galleryAddPic(String imagePath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(imagePath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
getActivity().sendBroadcast(mediaScanIntent);
Log.d(TAG,"savesucaff");
}
//end
/**
* {@link CaptureRequest.Builder} for the camera preview
*/
private CaptureRequest.Builder mPreviewRequestBuilder;
/**
* {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
*/
private CaptureRequest mPreviewRequest;
/**
* The current state of camera state for taking pictures.
*
* @see #mCaptureCallback
*/
private int mState = STATE_PREVIEW;
/**
* A {@link Semaphore} to prevent the app from exiting before closing the camera.
*/
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
/**
* Whether the current camera device supports Flash or not.
*/
private boolean mFlashSupported;
/**
* Orientation of the camera sensor
*/
private int mSensorOrientation;
/**
* A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
*/
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
// We have nothing to do when the camera preview is working normally.
break;
}
case STATE_WAITING_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
} else {
runPrecaptureSequence();
}
}
break;
}
case STATE_WAITING_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WAITING_NON_PRECAPTURE;
}
break;
}
case STATE_WAITING_NON_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
}
}
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureResult partialResult) {
// Log.d("cjc","partial");
process(partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
// Log.d("cjc","complete");
process(result);
}
};
/**
* Shows a {@link Toast} on the UI thread.
*
* @param text The message to show
*/
private void showToast(final String text) {
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
}
});
}
}
/**
* Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
* is at least as large as the respective texture view size, and that is at most as large as the
* respective max size, and whose aspect ratio matches with the specified value. If such size
* doesn't exist, choose the largest one that is at most as large as the respective max size,
* and whose aspect ratio matches with the specified value.
*
* @param choices The list of sizes that the camera supports for the intended output
* class
* @param textureViewWidth The width of the texture view relative to sensor coordinate
* @param textureViewHeight The height of the texture view relative to sensor coordinate
* @param maxWidth The maximum width that can be chosen
* @param maxHeight The maximum height that can be chosen
* @param aspectRatio The aspect ratio
* @return The optimal {@code Size}, or an arbitrary one if none were big enough
*/
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
// Collect the supported resolutions that are smaller than the preview Surface
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
public static Camera2BasicFragment newInstance() {
return new Camera2BasicFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_camera2_basic, container, false);
}
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
view.findViewById(R.id.picture).setOnClickListener(this);
view.findViewById(R.id.info).setOnClickListener(this);
//used for preview surface
mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
mTextureView2 = (AutoFitTextureView) view.findViewById(R.id.texture2);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
startBackgroundThread();
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (mTextureView2.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView2.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
@Override
public void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
private void requestCameraPermission() {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
} else {
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
ErrorDialog.newInstance(getString(R.string.request_permission))
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
/**
* Sets up member variables related to camera.
*
* @param width The width of available size for camera preview
* @param height The height of available size for camera preview
/**
* Sets up member variables related to camera.
*
* @param width The width of available size for camera preview
* @param height The height of available size for camera preview
*/
float a = 0;
float a2 = 0;
//逻辑相机ID(厂商分配)
private String logicCameraId;
//相机物理id 1
private String physicsCameraId1;
//相机物理id 2
private String physicsCameraId2;
private String physicsCameraId3;
@SuppressWarnings("SuspiciousNameCombination")
private void setUpCameraOutputs(int width, int height) {
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
CameraManager cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
List<String> useCameraList = new ArrayList<>();
String[] cameraIdList = cameraManager.getCameraIdList();
for (String cameraId : cameraIdList) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
Integer physicalCameraId = characteristics.get(CameraCharacteristics.LENS_FACING);
if (physicalCameraId != null && (physicalCameraId == CameraCharacteristics.LENS_FACING_BACK || physicalCameraId == CameraCharacteristics.LENS_FACING_FRONT)) {
String logicalCameraId = cameraId;
Log.d("Logical Camera ID", logicalCameraId);
useCameraList.add(logicalCameraId);
boolean isFrontCamera = (physicalCameraId == CameraCharacteristics.LENS_FACING_FRONT);
if (isFrontCamera) {
Log.d("Camera Type", "Front camera");
} else {
Log.d("Camera Type", "Back camera");
}
Set<String> physicalCameraIdSet = characteristics.getPhysicalCameraIds();
if (physicalCameraIdSet != null) {
for (String individualPhysicalCameraId : physicalCameraIdSet) {
Log.d("Physical Camera ID", individualPhysicalCameraId);
useCameraList.add(individualPhysicalCameraId);
CameraCharacteristics physicalCharacteristics = cameraManager.getCameraCharacteristics(individualPhysicalCameraId);
StreamConfigurationMap configurationMap = physicalCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (configurationMap != null) {
int[] outputFormats = configurationMap.getOutputFormats();
if (outputFormats != null && outputFormats.length > 0) {
Log.d("Physical Camera", individualPhysicalCameraId + " supports the following output formats:");
for (int format : outputFormats) {
Log.d("Output Format", String.valueOf(format));
}
} else {
Log.d("Physical Camera", individualPhysicalCameraId + " does not support any output formats");
}
}
// 判断物理相机是否是超广角摄像头
int[] distortionCorrectionModes = physicalCharacteristics.get(CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES);
if (distortionCorrectionModes != null && Arrays.asList(distortionCorrectionModes).contains(CameraCharacteristics.DISTORTION_CORRECTION_MODE_HIGH_QUALITY)) {
Log.d("Physical Camera", individualPhysicalCameraId + " is a wide-angle camera");
}
}
}
}
}
String[] cameraIds = cameraManager.getCameraIdList();
for (String cameraId : cameraIds) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
// 检查相机的硬件级别
Integer hardwareLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (hardwareLevel != null && (hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)) {
// 相机支持多摄像头会话
Log.d(TAG, "Camera ID: " + cameraId + " supports multi-camera session");
} else {
// 相机不支持多摄像头会话
Log.d(TAG, "Camera ID: " + cameraId + " does not support multi-camera session" + hardwareLevel);
Log.d(TAG, "a"+CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
Log.d(TAG, "b"+CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
}
}
Log.d(TAG, "asdfasdfasdfadf:"+useCameraList);
logicCameraId = useCameraList.get(0);
physicsCameraId1= useCameraList.get(1);
physicsCameraId2= useCameraList.get(2);
// physicsCameraId3= useCameraList.get(3);
//logical
String cameraId = "1";
CameraCharacteristics characteristics0
= manager.getCameraCharacteristics("1");
StreamConfigurationMap map0 = characteristics0.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//physical
CameraCharacteristics characteristics1
= manager.getCameraCharacteristics(physicsCameraId1);
StreamConfigurationMap map1 = characteristics1.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map1 == null) {
Log.d("cjc", "NULL map SCALER_STREAM_CONFIGURATION_MAP2");
}
assert map1 != null;
CameraCharacteristics characteristics2
= manager.getCameraCharacteristics(physicsCameraId2);
StreamConfigurationMap map2 = characteristics2.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map2 == null) {
Log.d("cjc", "NULL map SCALER_STREAM_CONFIGURATION_MAP3");
}
assert map2 != null;
// For still image captures, we use the largest available size.
Size largest0 = Collections.max(
Arrays.asList(map0.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea());
Size largest1 = Collections.max(
Arrays.asList(map1.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea());
Size largest2 = Collections.max(
Arrays.asList(map2.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea());
// a = characteristics1.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
// a2 = characteristics2.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
// Find out if we need to swap dimension to get the preview size relative to sensor
// coordinate.
int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
//noinspection ConstantConditions
mSensorOrientation = characteristics0.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
swappedDimensions = true;
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
swappedDimensions = true;
}
break;
default:
Log.e(TAG, "Display rotation is invalid: " + displayRotation);
}
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
int rotatedPreviewWidth = width;
int rotatedPreviewHeight = height;
int maxPreviewWidth = displaySize.x;
int maxPreviewHeight = displaySize.y;
if (swappedDimensions) {
rotatedPreviewWidth = height;
rotatedPreviewHeight = width;
maxPreviewWidth = displaySize.y;
maxPreviewHeight = displaySize.x;
}
if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
maxPreviewWidth = MAX_PREVIEW_WIDTH;
}
if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
}
// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
mPreviewSize = chooseOptimalSize(map0.getOutputSizes(SurfaceTexture.class),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
maxPreviewHeight, largest0);
//必须两个预览一起,只调3会bug,只调2没问题
// We fit the aspect ratio of TextureView to the size of preview we picked.
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(
mPreviewSize.getWidth(), mPreviewSize.getHeight());
mTextureView2.setAspectRatio(
mPreviewSize.getWidth(), mPreviewSize.getHeight());
} else {
mTextureView.setAspectRatio(
mPreviewSize.getHeight(), mPreviewSize.getWidth());
mTextureView2.setAspectRatio(
mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
// Check if the flash is supported.
Boolean available = characteristics0.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mFlashSupported = available == null ? false : available;
mImageReader1 = ImageReader.newInstance(largest1.getWidth(), largest1.getHeight(),
ImageFormat.JPEG, /*maxImages*/6);
mImageReader2 = ImageReader.newInstance(largest2.getWidth(), largest2.getHeight(),
ImageFormat.JPEG, /*maxImages*/12);
mImageReader1.setOnImageAvailableListener(
mOnImageAvailableListener1, mBackgroundHandler);
mImageReader2.setOnImageAvailableListener(
mOnImageAvailableListener2, mBackgroundHandler);
// Log.d(TAG,"asdfasdf!!!");
// DualCamera dualCamera = new DualCamera("1","2","3");
mCameraId = logicCameraId;
return;
} catch (NullPointerException e) {
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
ErrorDialog.newInstance(getString(R.string.camera_error))
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.
*/
private void openCamera(int width, int height) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestCameraPermission();
return;
}
setUpCameraOutputs(width, height);//done
//configureTransform(width, height);
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
if (mCameraDevice != null) {return;}
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
/**
* Closes the current {@link CameraDevice}.
*/
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
}
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
if (null != mImageReader1) {
mImageReader1.close();
mImageReader1 = null;
}
if (null != mImageReader2) {
mImageReader2.close();
mImageReader2 = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}
}
/**
/**
* Starts a background thread and its {@link Handler}.
*/
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
/**
* Stops the background thread and its {@link Handler}.
*/
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* Creates a new {@link CameraCaptureSession} for camera preview.
*/
@RequiresApi(api = Build.VERSION_CODES.P)
private void createCameraPreviewSession() {
try {
CameraManager cameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
String[] cameraIds = cameraManager.getCameraIdList();
for (String cameraId : cameraIds) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
// 检查相机的硬件级别
Integer hardwareLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (hardwareLevel != null && (hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)) {
// 相机支持多摄像头会话
Log.d(TAG, "Camera ID: " + cameraId + " supports multi-camera session");
} else {
// 相机不支持多摄像头会话
Log.d(TAG, "Camera ID: " + cameraId + " does not support multi-camera session");
}
}
SurfaceTexture texture = mTextureView.getSurfaceTexture();
SurfaceTexture texture2 = mTextureView2.getSurfaceTexture();
assert texture != null;
assert texture2 != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
texture2.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
Surface surface2 = new Surface(texture2);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mPreviewRequestBuilder.addTarget(surface2);
OutputConfiguration opc1 = new OutputConfiguration(surface);
opc1.setPhysicalCameraId(physicsCameraId1);
OutputConfiguration opc2 = new OutputConfiguration(surface2);
opc2.setPhysicalCameraId(physicsCameraId2);
OutputConfiguration opc3 = new OutputConfiguration(mImageReader1.getSurface());
opc3.setPhysicalCameraId(physicsCameraId1);
OutputConfiguration opc4 = new OutputConfiguration(mImageReader2.getSurface());
opc4.setPhysicalCameraId(physicsCameraId2);
List<OutputConfiguration> outputConfigsAll = Arrays.asList(opc1,opc2,opc3,opc4);
// Here, we create a CameraCaptureSession for camera preview.
SessionConfiguration sessionConfiguration = new SessionConfiguration(SessionConfiguration.SESSION_REGULAR,outputConfigsAll, AsyncTask.SERIAL_EXECUTOR,
new CameraCaptureSession.StateCallback(){
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE,0.0f);
// Flash is automatically enabled when necessary.
setAutoFlash(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(
@NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
});
mCameraDevice.createCaptureSession(sessionConfiguration);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* Configures the necessary {@link Matrix} transformation to `mTextureView`.
* This method should be called after the camera preview size is determined in
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
*
* @param viewWidth The width of `mTextureView`
* @param viewHeight The height of `mTextureView`
*/
private void configureTransform(int viewWidth, int viewHeight) {
Activity activity = getActivity();
if (null == mTextureView|| null == mTextureView2 || null == mPreviewSize || null == activity) {
return;
}
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
mTextureView.setTransform(matrix);
mTextureView2.setTransform(matrix);
}
/**
* Initiate a still image capture.
*/
private void takePicture() {
lockFocus();
}
/**
* Lock the focus as the first step for a still image capture.
*/
private void lockFocus() {
try {
// This is how to tell the camera to lock focus.
// mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
// CameraMetadata.CONTROL_AF_TRIGGER_START);
// Tell #mCaptureCallback to wait for the lock.
mState = STATE_WAITING_LOCK;
Log.d("cjc","1");
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* Run the precapture sequence for capturing a still image. This method should be called when
* we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
*/
private void runPrecaptureSequence() {
try {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
// Tell #mCaptureCallback to wait for the precapture sequence to be set.
mState = STATE_WAITING_PRECAPTURE;
Log.d("cjc","2");
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void logImageReaderDetails(ImageReader imageReader) {
int imageWidth = imageReader.getWidth();
int imageHeight = imageReader.getHeight();
int imageFormat = imageReader.getImageFormat();
int maxImages = imageReader.getMaxImages();
Surface imageReaderSurface = imageReader.getSurface();
Log.d(TAG, "ImageReader 宽度:" + imageWidth + ",高度:" + imageHeight);
Log.d(TAG, "ImageReader 格式:" + imageFormat);
Log.d(TAG, "ImageReader 最大图像数:" + maxImages);
Log.d(TAG, "ImageReader Surface:" + imageReaderSurface);
}
/**
* Capture a still picture. This method should be called when we get a response in
* {@link #mCaptureCallback} from both {@link #lockFocus()}.
*/
// public void captureStillPicture() {
// try {
// final Activity activity = getActivity();
// if (null == activity || null == mCameraDevice) {
// return;
// }
// // This is the CaptureRequest.Builder that we use to take a picture.
//
// //这里template不能用still_capture,猜测会造成两个摄像头抢而导致失败。除了这个其他template都可以
// //template_record 3摄像头出来是黑的
// //template_zero_shutter_lag延时严重
// //template_video_snapshot 34ms 拍摄之后卡顿
// //template_preview 20ms
// final CaptureRequest.Builder captureRequest1 =
// mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// captureRequest1.addTarget(mImageReader1.getSurface());
// captureRequest1.addTarget(mImageReader2.getSurface());
//
//// captureRequest1.set(CaptureRequest.DISTORTION_CORRECTION_MODE, CameraMetadata.DISTORTION_CORRECTION_MODE_OFF);
// // Use the same AE and AF modes as the preview.
// captureRequest1.set(CaptureRequest.CONTROL_AF_MODE,
// CaptureRequest.CONTROL_AF_MODE_OFF);
// captureRequest1.set(CaptureRequest.LENS_FOCUS_DISTANCE,0.0f);
// setAutoFlash(captureRequest1);
//
// // Orientation
// int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
// captureRequest1.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
//
//
//
// CameraCaptureSession.CaptureCallback CaptureCallback1
// = new CameraCaptureSession.CaptureCallback() {
//
// @Override
// public void onCaptureCompleted(@NonNull CameraCaptureSession session,
// @NonNull CaptureRequest request,
// @NonNull TotalCaptureResult result) {
// showToast("Saved: "+mFile2.toString());
// Log.d(TAG, mFile2.toString());
// unlockFocus();
// }
// };
//
// mCaptureSession.stopRepeating();
// mCaptureSession.abortCaptures();
// mCaptureSession.capture(captureRequest1.build(), CaptureCallback1, mBackgroundHandler);
//
// idx+=1;
// } catch (CameraAccessException e) {
// e.printStackTrace();
// }
// }
public void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// 创建用于拍摄图片的CaptureRequest.Builder对象
// 这里使用TEMPLATE_STILL_CAPTURE模板,但只设置一个目标表面,以便每个请求只执行一次拍摄操作
final CaptureRequest.Builder captureRequest1 =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequest1.addTarget(mImageReader1.getSurface());
captureRequest1.set(CaptureRequest.DISTORTION_CORRECTION_MODE, CameraMetadata.DISTORTION_CORRECTION_MODE_OFF);
// 使用与预览相同的AE和AF模式
captureRequest1.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_OFF);
captureRequest1.set(CaptureRequest.LENS_FOCUS_DISTANCE, 0.0f);
setAutoFlash(captureRequest1);
Log.d(TAG, "ImageReader 1 详情:");
logImageReaderDetails(mImageReader1);
final CaptureRequest.Builder captureRequest2 =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequest2.addTarget(mImageReader2.getSurface());
captureRequest2.set(CaptureRequest.DISTORTION_CORRECTION_MODE, CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY);
// 使用与预览相同的AE和AF模式
captureRequest2.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_OFF);
captureRequest2.set(CaptureRequest.LENS_FOCUS_DISTANCE, 0.0f);
setAutoFlash(captureRequest2);
Log.d(TAG, "ImageReader 2 详情:");
logImageReaderDetails(mImageReader2);
if (mImageReader1 != null && mImageReader2 != null &&
mImageReader1.getSurface() != null && mImageReader2.getSurface() != null) {
Log.d(TAG, "all right");
}
// 设置旋转角度
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureRequest1.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
captureRequest2.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
int frameCount = mImageReader1.getMaxImages();
Log.d(TAG, "frameCount:"+frameCount);
CameraCaptureSession.CaptureCallback captureCallback1 = new CameraCaptureSession.CaptureCallback() {
private boolean isFirstCaptureCompleted = false;
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
Image image = mImageReader1.acquireNextImage();
if (image != null) {
// 处理图像数据
Log.d(TAG, "have images1");}
else {
Log.d(TAG, "no have images1");
}
if (!isFirstCaptureCompleted) {
if (mFile1 != null) {
Log.d(TAG, "Saved: " + mFile1.toString());
}
Log.d(TAG, "mFile1 is null");
isFirstCaptureCompleted = true;
} else {
// 第二次拍摄完成后解锁焦点
unlockFocus();
}
}
};
CameraCaptureSession.CaptureCallback captureCallback2 = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
Image image = mImageReader2.acquireNextImage();
if (image != null) {
// 处理图像数据
Log.d(TAG, "have images");}
else {
Log.d(TAG, "no have images");
}
// // 触发 mOnImageAvailableListener2
// if (mOnImageAvailableListener2 != null) {
// mOnImageAvailableListener2.onImageAvailable(mImageReader2);
// }
if (mFile2 != null) {
Log.d(TAG, "Saved: " + mFile2.toString());
} else {
Log.e(TAG, "mFile2 is null");
unlockFocus();
}
// 解锁焦点
}
};
mCaptureSession.stopRepeating();
mCaptureSession.abortCaptures();
// 执行第一次拍摄操作:captureRequest1
mCaptureSession.capture(captureRequest1.build(), captureCallback1, mBackgroundHandler);
// 等待第一次拍摄完成后,再执行第二次拍摄操作:captureRequest2
mCaptureSession.capture(captureRequest2.build(), captureCallback2, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* Retrieves the JPEG orientation from the specified screen rotation.
*
* @param rotation The screen rotation.
* @return The JPEG orientation (one of 0, 90, 270, and 360)
*/
private int getOrientation(int rotation) {
// Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X)
// We have to take that into account and rotate JPEG properly.
// For devices with orientation of 90, we simply return our mapping from ORIENTATIONS.
// For devices with orientation of 270, we need to rotate the JPEG 180 degrees.
return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}
/**
* Unlock the focus. This method should be called when still image capture sequence is
* finished.
*/
private void unlockFocus() {
try {
// Reset the auto-focus trigger
// mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
// CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
setAutoFlash(mPreviewRequestBuilder);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
// After this, the camera will go back to the normal state of preview.
mState = STATE_PREVIEW;
Log.d("cjc","4");
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
mBackgroundHandler);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(250); // 休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
if(flag==1){
captureStillPicture();
}
}
}).start();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.picture) {
takePicture();
} else if (view.getId() == R.id.info) {
Activity activity = getActivity();
if (null != activity) {
new AlertDialog.Builder(activity)
.setMessage(R.string.intro_message)
.setPositiveButton(android.R.string.ok, null)
.show();
}
}
}
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
}
/**
* Saves a JPEG {@link Image} into the specified {@link File}.
*/
private static class ImageSaver implements Runnable {
/**
* The JPEG image
*/
private final Image mImage;
/**
* The file we save the image into.
*/
private final File mFile;
ImageSaver(Image image, File file) {
mImage = image;
mFile = file;
}
@Override
public void run() {
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
output.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* Compares two {@code Size}s based on their areas.
*/
static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
/**
* Shows an error message dialog.
*/
public static class ErrorDialog extends DialogFragment {
private static final String ARG_MESSAGE = "message";
public static ErrorDialog newInstance(String message) {
ErrorDialog dialog = new ErrorDialog();
Bundle args = new Bundle();
args.putString(ARG_MESSAGE, message);
dialog.setArguments(args);
return dialog;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
return new AlertDialog.Builder(activity)
.setMessage(getArguments().getString(ARG_MESSAGE))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
activity.finish();
}
})
.create();
}
}
/**
* Shows OK/Cancel confirmation dialog about camera permission.
*/
public static class ConfirmationDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Fragment parent = getParentFragment();
return new AlertDialog.Builder(getActivity())
.setMessage(R.string.request_permission)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
parent.requestPermissions(new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Activity activity = parent.getActivity();
if (activity != null) {
activity.finish();
}
}
})
.create();
}
}
}
captureCallback2是被调用的,是imagereader2没有配置好么?
相似问题