CameraManager——Camera的过时替代方法
CameraManager
用于檢測,表征和連接的系統(tǒng)服務(wù)管理器 CameraDevices。
有關(guān)與相機設(shè)備通信的更多詳細(xì)信息,請閱讀相機開發(fā)人員指南或camera2 包文檔。
此類的實例,必須使用能夠獲得Context.getSystemService(Class)與所述參數(shù)CameraManager.class或Context.getSystemService(String)使用參數(shù)Context.CAMERA_SERVICE。
getCameraIdList
public String[] getCameraIdList ()
按標(biāo)識符返回當(dāng)前連接的攝像機設(shè)備列表,包括其他攝像機API客戶端可能正在使用的攝像機。
不可移動攝像頭使用從0開始的整數(shù)作為其標(biāo)識符,而可移動攝像頭具有每個單獨設(shè)備的唯一標(biāo)識符,即使它們是相同的模型
返回
String[]:當(dāng)前連接的攝像機設(shè)備列表。該值永遠(yuǎn)不會為空。
openCamera
public void openCamera(String cameraId,CameraDevice.StateCallback callback,Handler handler)
- 打開與具有給定ID的攝像機的連接。
- 使用getCameraIdList()以獲取可用的相機設(shè)備的列表。請注意,即使列出了id,如果設(shè)備在對getCameraIdList()和openCamera(String, CameraDevice.StateCallback, Handler)的呼叫之間斷開連接,或者如果優(yōu)先級較高的攝像機API客戶端開始使用攝像機設(shè)備,則打開可能會失敗。
- 從API第23級開始,由于設(shè)備的優(yōu)先級較低,調(diào)用了cameramanamanager.availabilityCallback.oncameraunavailable(string)回調(diào)的設(shè)備,當(dāng)調(diào)用的camera api客戶端的優(yōu)先級高于當(dāng)前camera ap時,仍可以通過調(diào)用此方法打開后臺camera api客戶端。使用此設(shè)備的客戶端,一般來說,如果應(yīng)用程序進(jìn)程中正在運行Top、Foreground活動,則在訪問相機時,進(jìn)程將被賦予最高優(yōu)先級,并且即使另一個相機API客戶端正在使用相機設(shè)備,此方法也將成功。任何以這種方式失去對相機控制的低優(yōu)先級應(yīng)用程序都將收到cameradevice.StateCallback.OnDisconnected(cameradevice)回調(diào)。
- 一旦相機成功打開,CameraDevice.StateCallback.onOpened(CameraDevice)將使用新打開的方式調(diào)用CameraDevice。然后可以通過調(diào)用CameraDevice.createCaptureSession(SessionConfiguration)和 設(shè)置攝像機設(shè)備進(jìn)行操作CameraDevice.createCaptureRequest(int)
如果在此函數(shù)調(diào)用返回后初始化期間攝像機斷開連接,則將跳過CameraDevice.StateCallback.onDisconnected(CameraDevice)與處于斷開狀態(tài)的CameraDevice(以及CameraDevice.StateCallback.onOpened(CameraDevice))。
如果打開相機設(shè)備失敗,則將調(diào)用設(shè)備回調(diào)的onError方法,并且相機設(shè)備上的后續(xù)調(diào)用將拋出CameraAccessException。 - 需要CAMERA權(quán)限。
參數(shù)
cameraId:String:要打開的攝像機設(shè)備的唯一標(biāo)識符,該值不得為null。
callback:CameraDevice.StateCallback:打開相機后調(diào)用的回調(diào),該值不得為null。
handler:應(yīng)該調(diào)用回調(diào)的handler或null,handler的參數(shù)使用當(dāng)前線程的循環(huán)器。
openCamera
public void openCamera (String cameraId,
Executor executor,
CameraDevice.StateCallback callback)
使用給定的ID打開相機的連接。
此方法的行為與openCamera(String,StateCallback,Handler)的行為相匹配,除了它使用Executor作為參數(shù)而不是Handler。
需要相機權(quán)限
參數(shù)
cameraId:要打開的攝像機設(shè)備的唯一標(biāo)識符,該值不得為null。
executor:調(diào)用回調(diào)時將使用的executor。這個值不能為null。通過此Executor調(diào)度回調(diào)和偵聽器事件,提供一種簡單的方法來控制使用哪個線程。 要通過應(yīng)用程序的主線程調(diào)度事件,可以使用Context.getMainExecutor()。 要通過共享線程池調(diào)度事件,您可以使用AsyncTask.THREAD_POOL_EXECUTOR.
registerAvailabilityCallback
public void registerAvailabilityCallback (Executor executor,
CameraManager.AvailabilityCallback callback)
注冊一個回調(diào)以獲得有關(guān)相機設(shè)備可用性的通知。
此方法的行為與registerAvailabilityCallback(AvailabilityCallback,Handler)的行為匹配,除了它使用Executor作為參數(shù)而不是Handler。
registerAvailabilityCallback
public void registerAvailabilityCallback (CameraManager.AvailabilityCallback callback,
Handler handler)
- 注冊一個回調(diào)以獲得有關(guān)相機設(shè)備可用性的通知。
- 再次注冊相同的回調(diào)將替換handler提供的新回調(diào)。
- 第一次注冊回調(diào)時,會立即調(diào)用所有當(dāng)前已知的攝像機設(shè)備的可用性狀態(tài)。
- 每當(dāng)相機API客戶端打開相機設(shè)備時,都會調(diào)用CameraManager.AvailabilityCallback.onCameraUnavailable(String)。 從API級別23開始,其他相機API客戶端仍然可以打開這樣的相機設(shè)備,如果它們具有比相機設(shè)備的現(xiàn)有客戶端更高的優(yōu)先級,則驅(qū)逐現(xiàn)有客戶端。 有關(guān)詳細(xì)信息,請參閱open()。
- 由于此回調(diào)將在相機服務(wù)中注冊,因此請務(wù)必在不再需要時取消注冊; 否則回調(diào)將繼續(xù)無限期地接收事件,并可能阻止其他資源被釋放。 具體來說,回調(diào)將獨立于一般活動生命周期而獨立于各個CameraManager實例的狀態(tài)進(jìn)行調(diào)用。
registerTorchCallback
public void registerTorchCallback (CameraManager.TorchCallback callback,Handler handler)
- 注冊一個回調(diào)以獲得有關(guān)torch 模式狀態(tài)的通知。
- 再次注冊相同的回調(diào)將使用提供的新處理程序替換處理程序。
第一次注冊回調(diào)時,立即使用閃光燈裝置的所有當(dāng)前已知相機設(shè)備的手電筒模式狀態(tài)調(diào)用。 - 由于此回調(diào)將在相機服務(wù)中注冊,因此請務(wù)必在不再需要時取消注冊; 否則回調(diào)將繼續(xù)無限期地接收事件,并可能阻止其他資源被釋放。 具體來說,回調(diào)將獨立于一般活動生命周期而獨立于各個CameraManager實例的狀態(tài)進(jìn)行調(diào)用。
registerTorchCallback
注冊一個回調(diào)以獲得有關(guān)torch 模式狀態(tài)的通知。
此方法的行為與registerTorchCallback(TorchCallback, Handler)的行為匹配,除了它使用Executor作為參數(shù)而不是Handler。
setTorchMode
public void setTorchMode (String cameraId,
boolean enabled)
- 無需打開相機設(shè)備即可設(shè)置給定ID的相機的閃光燈組件的手電筒模式。
- 使用getCameraIdList()獲取可用攝像頭設(shè)備列表,并使用getCameraCharacteristics(String)檢查攝像頭設(shè)備是否具有閃光燈組件。 請注意,即使相機設(shè)備配有閃光燈組件,如果正在使用打開手電筒模式所需的相機設(shè)備或其他相機資源,則開啟手電筒模式可能會失敗
- 如果調(diào)用setTorchMode(String,boolean)成功打開或關(guān)閉手電筒模式,將調(diào)用CameraManager.TorchCallback.onTorchModeChanged(String,boolean)。 但是,即使打開手電筒模式成功,應(yīng)用程序也不擁有閃光燈組件或相機設(shè)備的專有權(quán)。 當(dāng)閃光燈所屬的攝像機設(shè)備不可用或其他攝像機資源使手電筒打開時,手電筒模式將關(guān)閉并變?yōu)椴豢捎?#xff08;將調(diào)用CameraManager.TorchCallback.onTorchModeUnavailable(String))。 此外,其他應(yīng)用程序可以自由調(diào)用setTorchMode(String,boolean)來關(guān)閉手電筒模式(將調(diào)用CameraManager.TorchCallback.onTorchModeChanged(String,boolean))。 如果打開手電筒模式的最新應(yīng)用程序退出,則將關(guān)閉手電筒模式。
unregisterAvailabilityCallback
public void unregisterAvailabilityCallback (CameraManager.AvailabilityCallback callback)
刪除以前添加的回調(diào); 回調(diào)將不再接收連接和斷開連接回調(diào)。
刪除未注冊無用的回調(diào)。
unregisterTorchCallback
public void unregisterTorchCallback (CameraManager.TorchCallback callback)
刪除以前添加的回調(diào); 回調(diào)將不再接收手電筒模式狀態(tài)回調(diào)。
刪除未注冊無用的回調(diào)。
Camera使用示例
package com.yds.animation.camera;import android.support.v4.app.Fragment;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.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.app.DialogFragment; import android.support.v4.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 com.yds.animation.camerademo.R;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.concurrent.Semaphore; import java.util.concurrent.TimeUnit;public class Camera2BasicFragment extends Fragmentimplements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {/*** 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";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}.*/private static final String TAG = "Camera2BasicFragment";/*** 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() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {openCamera(width, height);}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {configureTransform(width, height);}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {return true;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture texture) {}};/*** ID of the current {@link CameraDevice}.*/private String mCameraId;/*** An {@link AutoFitTextureView} for camera preview.*/private AutoFitTextureView mTextureView;/*** A {@link CameraCaptureSession } for camera preview.*/private CameraCaptureSession mCaptureSession;/*** A reference to the opened {@link CameraDevice}.*/private CameraDevice mCameraDevice;/*** The {@link android.util.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() {@Overridepublic void onOpened(@NonNull CameraDevice cameraDevice) {// This method is called when the camera is opened. We start camera preview here.mCameraOpenCloseLock.release();mCameraDevice = cameraDevice;createCameraPreviewSession();}@Overridepublic void onDisconnected(@NonNull CameraDevice cameraDevice) {mCameraOpenCloseLock.release();cameraDevice.close();mCameraDevice = null;}@Overridepublic 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;/*** A {@link Handler} for running tasks in the background.*/private Handler mBackgroundHandler;/*** An {@link ImageReader} that handles still image capture.*/private ImageReader mImageReader;/*** This is the output file for our picture.*/private File mFile;/*** This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a* still image is ready to be saved.*/private final ImageReader.OnImageAvailableListener mOnImageAvailableListener= new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));}};/*** {@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 devicesInteger 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 devicesInteger 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 devicesInteger aeState = result.get(CaptureResult.CONTROL_AE_STATE);if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {mState = STATE_PICTURE_TAKEN;captureStillPicture();}break;}}}@Overridepublic void onCaptureProgressed(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull CaptureResult partialResult) {process(partialResult);}@Overridepublic void onCaptureCompleted(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull TotalCaptureResult result) {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() {@Overridepublic 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 SurfaceList<Size> bigEnough = new ArrayList<>();// Collect the supported resolutions that are smaller than the preview SurfaceList<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();}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_camera2_basic, container, false);}@Overridepublic void onViewCreated(final View view, Bundle savedInstanceState) {view.findViewById(R.id.picture).setOnClickListener(this);view.findViewById(R.id.info).setOnClickListener(this);mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);}@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");}@Overridepublic 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 (mTextureView.isAvailable()) {openCamera(mTextureView.getWidth(), mTextureView.getHeight());} else {mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);}}@Overridepublic 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);}}@Overridepublic 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*/@SuppressWarnings("SuspiciousNameCombination")private void setUpCameraOutputs(int width, int height) {Activity activity = getActivity();CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);try {for (String cameraId : manager.getCameraIdList()) {CameraCharacteristics characteristics= manager.getCameraCharacteristics(cameraId);// We don't use a front facing camera in this sample.Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {continue;}StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);if (map == null) {continue;}// For still image captures, we use the largest available size.Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),new CompareSizesByArea());mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),ImageFormat.JPEG, /*maxImages*/2);mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);// Find out if we need to swap dimension to get the preview size relative to sensor// coordinate.int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();//noinspection ConstantConditionsmSensorOrientation = characteristics.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(map.getOutputSizes(SurfaceTexture.class),rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,maxPreviewHeight, largest);// 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());} else {mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());}// Check if the flash is supported.Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);mFlashSupported = available == null ? false : available;mCameraId = cameraId;return;}} catch (CameraAccessException e) {e.printStackTrace();} 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);}}/*** 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);configureTransform(width, height);Activity activity = getActivity();CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);try {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 != mImageReader) {mImageReader.close();mImageReader = 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.*/private void createCameraPreviewSession() {try {SurfaceTexture texture = mTextureView.getSurfaceTexture();assert texture != null;// We configure the size of default buffer to be the size of camera preview we want.texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());// This is the output Surface we need to start preview.Surface surface = new Surface(texture);// We set up a CaptureRequest.Builder with the output Surface.mPreviewRequestBuilder= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);mPreviewRequestBuilder.addTarget(surface);// Here, we create a CameraCaptureSession for camera preview.mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {// The camera is already closedif (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_CONTINUOUS_PICTURE);// 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();}}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {showToast("Failed");}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}/*** Configures the necessary {@link android.graphics.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 == 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);}/*** 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;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 {// This is how to tell the camera to trigger.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;mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}/*** Capture a still picture. This method should be called when we get a response in* {@link #mCaptureCallback} from both {@link #lockFocus()}.*/private 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.final CaptureRequest.Builder captureBuilder =mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);captureBuilder.addTarget(mImageReader.getSurface());// Use the same AE and AF modes as the preview.captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);setAutoFlash(captureBuilder);// Orientationint rotation = activity.getWindowManager().getDefaultDisplay().getRotation();captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));CameraCaptureSession.CaptureCallback CaptureCallback= new CameraCaptureSession.CaptureCallback() {@Overridepublic void onCaptureCompleted(@NonNull CameraCaptureSession session,@NonNull CaptureRequest request,@NonNull TotalCaptureResult result) {showToast("Saved: " + mFile);Log.d(TAG, mFile.toString());unlockFocus();}};mCaptureSession.stopRepeating();mCaptureSession.abortCaptures();mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);} 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 triggermPreviewRequestBuilder.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;mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.picture: {takePicture();break;}case 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();}break;}}}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;}@Overridepublic 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> {@Overridepublic int compare(Size lhs, Size rhs) {// We cast here to ensure the multiplications won't overflowreturn 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@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {activity.finish();}}).create();}}/*** Shows OK/Cancel confirmation dialog about camera permission.*/public static class ConfirmationDialog extends DialogFragment {@NonNull@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {parent.requestPermissions(new String[]{Manifest.permission.CAMERA},REQUEST_CAMERA_PERMISSION);}}).setNegativeButton(android.R.string.cancel,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Activity activity = parent.getActivity();if (activity != null) {activity.finish();}}}).create();}}}總結(jié)
以上是生活随笔為你收集整理的CameraManager——Camera的过时替代方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑远程之路
- 下一篇: 计算机组成原理---中央处理器