Android Camera2使用

1. 相机使用流程

图1.jpg

2. SurfaceView

/**
 * Android 5.0 使用Camera2 照相
 * 使用SurfaceView显示
 * 主要步骤:
 * 1. 获得摄像头管理器CameraManager mCameraManager,mCameraManager.openCamera()来打开摄像头
 * 2. 指定要打开的摄像头,并创建openCamera()所需要的CameraDevice.StateCallback stateCallback
 * 3. 在CameraDevice.StateCallback stateCallback中调用takePreview(),这个方法中,使用CaptureRequest.Builder创建预览需要的CameraRequest,并初始化了CameraCaptureSession,最后调用了setRepeatingRequest(previewRequest, null, childHandler)进行了预览
 * 4. 点击拍照按钮,调用takePicture(),这个方法内,最终调用了capture(mCaptureRequest, null, childHandler)
 * 5. 在new ImageReader.OnImageAvailableListener(){}回调方法中,将拍照拿到的图片进行展示
 */
public class CameraSurfaceFragment extends Fragment {
  /**照相机设备请求码*/
  private static final int REQUEST_CAMERA_CODE = 0x100;
  /**拍照*/
  private Button mBtnTake;
  /**显示拍照好的图片*/
  private ImageView mIvShow;
  /**预览窗口*/
  private SurfaceView mSurfaceView;
  /**预览窗口Holder*/
  private SurfaceHolder mSurfaceHolder;
  /**子线程Handler*/
  private Handler mChildHandler;
  /**主线程Handler*/
  private Handler mMainHandler;
  /**照相机ID,标识前置,后置*/
  private String mCameraId;
  /**图片读取器*/
  private ImageReader mImageReader;
  /**摄像头管理者*/
  private CameraManager mCameraManager;
  /**照相机设备*/
  private CameraDevice mCameraDevice;
  /**照相会话*/
  private CameraCaptureSession mCameraCaptureSession;
  /**方向列表*/
  private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
  
  /**
   * 摄像头状态监听
   */
  private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
      // 打开摄像头
      mCameraDevice = camera;
      // 开启预览
      takePreview();
    }
  
    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
      // 关闭摄像头
      if (null != mCameraDevice) {
        // 关闭摄像头
        mCameraDevice.close();
        mCameraDevice = null;
      }
    }
  
    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
      // 摄像头异常
      Toast.makeText(getContext(), "摄像头开启失败", Toast.LENGTH_SHORT).show();
    }
  };
  
  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);
  }
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_camera_surface, container, false);
    initView(root);
    initListener();
    return root;
  }
  
  /**
   * 初始化View
   */
  private void initView(View view) {
    // 绑定View
    mIvShow = view.findViewById(R.id.iv_show);
    mBtnTake = view.findViewById(R.id.btn_take);
    mSurfaceView = view.findViewById(R.id.sv_camera);
    // 获取Holder
    mSurfaceHolder = mSurfaceView.getHolder();
    // 设置屏幕常量
    mSurfaceHolder.setKeepScreenOn(true);
    // 设置SurfaceView回调
    mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
      @Override
      public void surfaceCreated(SurfaceHolder holder) {
        // SurfaceView 创建
        initCamera();
      }
  
      @Override
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // SurfaceView 改变
      }
  
      @Override
      public void surfaceDestroyed(SurfaceHolder holder) {
        // SurfaceView 销毁
        // 销毁照相机设备
        if (null != mCameraDevice) {
          mCameraDevice.close();
          mCameraDevice = null;
        }
      }
    });
  }
  
  /**
   * 初始化监听器
   */
  private void initListener() {
    mBtnTake.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        takePicture();
      }
      
    });
  }
  
  /**
   * 初始化照相机
   */
  private void initCamera() {
    // 创建Handler线程并启动
    HandlerThread handlerThread = new HandlerThread("Camera");
    handlerThread.start();
    // 创建子线程Handler
    mChildHandler = new Handler(handlerThread.getLooper());
    // 创建主线程Handler
    mMainHandler = new Handler(Looper.getMainLooper());
    // 设置后置摄像头ID
    mCameraId = String.valueOf(CameraCharacteristics.LENS_FACING_FRONT);
    // 创建图片读取器
    mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG, 1);
    // 图片读取器设置图片可用监听
    mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
      @Override
      public void onImageAvailable(ImageReader reader) {
        showImage(reader);
      }
    }, mMainHandler);
    // 获取摄像头管理
    mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
    // 打开摄像头
    try {
      if (ActivityCompat.checkSelfPermission
              (getContext(), Manifest.permission.CAMERA)
              != PackageManager.PERMISSION_GRANTED) {
        // 申请权限
        requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_CODE);
      } else {
        // 打开摄像头
        mCameraManager.openCamera(mCameraId, mStateCallback, mMainHandler);
      }
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (REQUEST_CAMERA_CODE == requestCode) {
      // 权限允许
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        try {
          if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
          }
          mCameraManager.openCamera(mCameraId, mStateCallback, mMainHandler);
        } catch (CameraAccessException e) {
          e.printStackTrace();
        }
      } else {
        // 权限拒绝
        Toast.makeText(getContext(), "无权限", Toast.LENGTH_SHORT).show();
      }
    }
  }
  
  /**
   * 图片可用后,读取并显示图片
   * @param reader 图片读取器
   */
  private void showImage(ImageReader reader) {
    // 拿到图片数据
    Image image = reader.acquireNextImage();
    // 获取字节缓冲
    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
    // 创建与缓冲区相同的字节数组
    byte[] bytes = new byte[buffer.remaining()];
    // 将数据读取字节数组
    buffer.get(bytes);
    // 创建图片
    final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    // 显示图片
    if (null != bitmap) {
      mIvShow.setImageBitmap(bitmap);
    }
  }
  
  /**
   * 预览
   */
  private void takePreview() {
    try {
      // 创建预览需要的CaptureRequest.Builder
      final CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
      // 将SurfaceView的surface作为Builder的目标
      builder.addTarget(mSurfaceHolder.getSurface());
      // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
      mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
          // 检测设备是否为空
          if (null == mCameraDevice) return;
          // 配置
          // 当摄像头已经准备好时,开始显示预览
          mCameraCaptureSession = session;
          try {
            // 自动对焦
            builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // 打开闪光灯
            builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            // 显示预览
            CaptureRequest request = builder.build();
            // 会话设置重复请求
            mCameraCaptureSession.setRepeatingRequest(request, null, mChildHandler);
          } catch (CameraAccessException e) {
            e.printStackTrace();
          }
        }
  
        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
          Toast.makeText(getContext(), "配置失败", Toast.LENGTH_SHORT).show();
        }
      }, mChildHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * 拍照
   */
  private void takePicture() {
    // 判断设备是否为空
    if (null == mCameraDevice) return;
    // 创建拍照需要的CaptureRequest.Builder
    final CaptureRequest.Builder builder;
    try {
      // 创建拍照请求
      builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
      // 将imageReader的surface作为CaptureRequest.Builder的木白哦
      builder.addTarget(mImageReader.getSurface());
      // 自动对焦
      builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
      // 自动曝光
      builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
      // 获取手机方向
      int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
      // 根据设备方向计算设置照片的方向
      builder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
      // 拍照
      CaptureRequest request = builder.build();
      // 拍照会话执行拍照
      mCameraCaptureSession.capture(request, null, mChildHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
}

3. TextureView

/**
 * Camera2 与 Texture使用
 */
public class CameraTextureFragment extends Fragment {
  /**相机权限请求标识*/
  private static final int REQUEST_CAMERA_CODE = 0x100;
  /**预览*/
  private TextureView mTextureView;
  /**拍照按钮*/
  private Button mBtnTake;
  /**图片*/
  private ImageView mImageView;
  /**照相机ID,标识前置后置*/
  private String mCameraId;
  /**相机尺寸*/
  private Size mCaptureSize;
  /**图像读取者*/
  private ImageReader mImageReader;
  /**图像主线程Handler*/
  private Handler mCameraHandler;
  /**相机设备*/
  private CameraDevice mCameraDevice;
  /**预览大小*/
  private Size mPreviewSize;
  /**相机请求*/
  private CaptureRequest.Builder mCameraCaptureBuilder;
  /**相机拍照捕获会话*/
  private CameraCaptureSession mCameraCaptureSession;
  /**相机管理者*/
  private CameraManager mCameraManager;
  /**相机设备状态回调*/
  private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
      // 打开
      mCameraDevice = camera;
      // 开始预览
      takePreview();
    }
  
    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
      // 断开连接
      camera.close();
      mCameraDevice = null;
    }
  
    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
      // 异常
      camera.close();
      mCameraDevice = null;
    }
  };
  
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_camera_texture, container, false);
    initView(root);
    initListener();
    return root;
  }
  
  /**
   * 初始化View
   */
  private void initView(View view) {
    // 初始化View
    mImageView = view.findViewById(R.id.iv_show);
    mTextureView = view.findViewById(R.id.tv_camera);
    mBtnTake = view.findViewById(R.id.btn_take);
  }
  
  @Override
  public void onResume() {
    super.onResume();
    mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
      @Override
      public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        // SurfaceTexture可用
        // 设置相机参数并打开相机
        setUpCamera(width, height);
        openCamera();
      }
  
      @Override
      public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // SurfaceTexture大小改变
      }
  
      @Override
      public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        // SurfaceTexture 销毁
        return false;
      }
  
      @Override
      public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        // SurfaceTexture 更新
      }
    });
  }
  
  /**
   * 打开相机
   */
  private void openCamera() {
    // 获取照相机管理者
    mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
    try {
      if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_CODE);
        return;
      }
      // 打开相机
      mCameraManager.openCamera(mCameraId, mStateCallback, mCameraHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (REQUEST_CAMERA_CODE == requestCode) {
      // 权限允许
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        try {
          if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
          }
          mCameraManager.openCamera(mCameraId, mStateCallback, mCameraHandler);
        } catch (CameraAccessException e) {
          e.printStackTrace();
        }
      } else {
        // 权限拒绝
        Toast.makeText(getContext(), "无权限", Toast.LENGTH_SHORT).show();
      }
    }
  }
  
  /**
   * 设置相机参数
   * @param width 宽度
   * @param height 高度
   */
  private void setUpCamera(int width, int height) {
    // 创建Handler
    mCameraHandler = new Handler(Looper.getMainLooper());
    // 获取摄像头的管理者
    CameraManager cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
    try {
      // 遍历所有摄像头
      for (String cameraId : cameraManager.getCameraIdList()) {
        // 相机特性
        CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
        // 获取摄像头是前置还是后置
        Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
        // 此处默认打开后置摄像头
        if (null != facing && CameraCharacteristics.LENS_FACING_FRONT == facing)  continue;
        // 获取StreamConfigurationMap,管理摄像头支持的所有输出格式和尺寸
        StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        assert map != null;
        // 根据TextureView的尺寸设置预览尺寸
        mPreviewSize = getOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height);
        // 获取相机支持的最大拍照尺寸
        mCaptureSize = 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.getHeight() * rhs.getWidth());
                  }
                });
        // 此处ImageReader用于拍照所需
        setupImageReader();
        // 为摄像头赋值
        mCameraId = cameraId;
        break;
      }
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * 设置ImageReader
   */
  private void setupImageReader() {
    // 2代表ImageReader中最多可以获取两帧图像流
    mImageReader = ImageReader.newInstance(mCaptureSize.getWidth(), mCaptureSize.getHeight(), ImageFormat.JPEG, 1);
    // 设置图像可用监听
    mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
      @Override
      public void onImageAvailable(ImageReader reader) {
        // 获取图片
        final Image image = reader.acquireNextImage();
        // 提交任务,保存图片
        mCameraHandler.post(new ImageSaver(image));
        // 更新UI
        getActivity().runOnUiThread(new Runnable() {
          @Override
          public void run() {
            // 获取字节缓冲区
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            // 创建数组之前调用此方法,恢复默认设置
            buffer.rewind();
            // 创建与缓冲区内容大小相同的数组
            byte[] bytes = new byte[buffer.remaining()];
            // 从缓冲区存入字节数组,读取完成之后position在末尾
            buffer.get(bytes);
            // 获取Bitmap图像
            final Bitmap bitmap =  BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            // 显示
            if (null != bitmap) {
              mImageView.setImageBitmap(bitmap);
            }
            
          }
        });
      }
    }, mCameraHandler);
  }
  
  /**
   * 选择SizeMap中大于并且最接近width和height的size
   * @param sizeMap 可选的尺寸
   * @param width 宽
   * @param height 高
   * @return 最接近width和height的size
   */
  private Size getOptimalSize(Size[] sizeMap, int width, int height) {
    // 创建列表
    List<Size> sizeList = new ArrayList<>();
    // 遍历
    for (Size option : sizeMap) {
      // 判断宽度是否大于高度
      if (width > height) {
        if (option.getWidth() > width && option.getHeight() > height) {
          sizeList.add(option);
        }
      } else {
        if (option.getWidth() > height && option.getHeight() > width) {
          sizeList.add(option);
        }
      }
    }
    // 判断存储Size的列表是否有数据
    if (sizeList.size() > 0) {
      return Collections.min(sizeList, new Comparator<Size>() {
        @Override
        public int compare(Size lhs, Size rhs) {
          return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight());
        }
      });
    }
    return sizeMap[0];
  }
  
  /**
   * 设置监听
   */
  private void initListener() {
    mBtnTake.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        takePicture();
      }
    });
  }
  
  /**
   * 预览
   */
  private void takePreview(){
    // 获取SurfaceTexture
    SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
    // 设置默认的缓冲大小
    surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    // 创建Surface
    Surface previewSurface = new Surface(surfaceTexture);
    try {
      // 创建预览请求
      mCameraCaptureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
      // 将previewSurface添加到预览请求中
      mCameraCaptureBuilder.addTarget(previewSurface);
      // 创建会话
      mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
          try {
            // 配置
            CaptureRequest captureRequest = mCameraCaptureBuilder.build();
            // 設置session
            mCameraCaptureSession = session;
            // 设置重复预览请求
            mCameraCaptureSession.setRepeatingRequest(captureRequest, null, mCameraHandler);
          } catch (CameraAccessException e) {
            e.printStackTrace();
          }
        }
  
        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
          // 配置失败
        }
      }, mCameraHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * 拍照
   */
  private void takePicture() {
    try {
      // 设置触发
      mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
      mCameraCaptureBuilder.addTarget(mImageReader.getSurface());
      // 拍照
      mCameraCaptureSession.capture(mCameraCaptureBuilder.build(), null, mCameraHandler);
    } catch (CameraAccessException e) {
      Toast.makeText(getActivity(), "异常", Toast.LENGTH_SHORT).show();
      e.printStackTrace();
    }
  }
  
  /**
   * 保存图片任务
   */
  private class ImageSaver implements Runnable {
    /**图像*/
    private Image mImage;
    ImageSaver(Image image) {
      this.mImage = image;
    }
  
    @Override
    public void run() {
      // 获取字节缓冲区
      ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
      // 创建数组之前调用此方法,恢复默认设置--重要
      buffer.rewind();
      // 创建与字节缓冲区大小相同的字节数组
      byte[] data = new byte[buffer.remaining()];
      // 将数据读取字节数组
      buffer.get(data);
      // 获取缓存路径
      String path = getActivity().getExternalCacheDir().getPath();
      // 获取时间戳
      String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
      // 文件名
      String fileName = path + "/IMG_" + timeStamp + ".jpg";
      // 创建文件输出流
      FileOutputStream fos = null;
      try {
        // 初始化文件输出流
        fos = new FileOutputStream(fileName);
        // 将数据写入文件
        fos.write(data, 0, data.length);
        // 刷新缓冲区
        fos.flush();
      } catch (IOException e) {
        e.printStackTrace();
      } finally {
        if (null != fos) {
          try {
            fos.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
      }
    }
  }
}

4. 多功能相机

  • 切换摄像头
  /**
   * 后置摄像头
   */
  private static final int CAMERA_FRONT = CameraCharacteristics.LENS_FACING_FRONT;
  /**
   * 前置摄像头
   */
  private static final int CAMERA_BACK = CameraCharacteristics.LENS_FACING_BACK;
  /**
   * 照相机ID,标识前置后置
   */
  private String mCameraId;

  /**
   * 切换前后摄像头
   */
  private void switchCamera() {
    if (String.valueOf(CAMERA_FRONT).equals(mCameraId)) {
      // 后置
      mCameraId = String.valueOf(CAMERA_BACK);
    } else if (String.valueOf(CAMERA_BACK).equals(mCameraId)) {
      // 前置
      mCameraId = String.valueOf(CAMERA_FRONT);
    }
    closeCamera();
    reOpenCamera();
  }
  
  /**
   * 重新打开摄像头
   */
  private void reOpenCamera() {
    if (mTextureView.isAvailable()) {
      openCamera();
    } else {
      setTextureListener();
    }
  }
  
  /**
   * 关闭摄像头
   */
  private void closeCamera() {
    if (null != mCameraCaptureSession) {
      mCameraCaptureSession.close();
      mCameraCaptureSession = null;
    }
    if (null != mCameraDevice) {
      mCameraDevice.close();
      mCameraDevice = null;
    }
    if (null != mImageReader) {
      mImageReader.close();
      mImageReader = null;
    }
  }
  • 延时拍摄
  /**
   * 无延时
   */
  private static final int DELAY_ZERO = 0;
  /**
   * 延时3秒
   */
  private static final int DELAY_THREE = 3;
  /**
   * 延时10秒
   */
  private static final int DELAY_TEN = 10;
  
  /**
   * 延时拍摄
   */
  private void delayTake() {
    switch (mDelayTime) {
      case DELAY_ZERO:
        mDelayTime = DELAY_THREE;
        break;
      case DELAY_THREE:
        mDelayTime = DELAY_TEN;
        break;
      case DELAY_TEN:
        mDelayTime = DELAY_ZERO;
        break;
    }
    mBtnDelay.setText("延时" + mDelayTime + "秒");
    if (mDelayTime == DELAY_ZERO) {
      takePicture();
    } else {
      // 定时器
      new CountDownTimer(mDelayTime * 1000, 1000) {
        
        @Override
        public void onTick(long millisUntilFinished) {
          mBtnDelay.setText(String.valueOf(millisUntilFinished/1000) + "秒");
        }
        
        @Override
        public void onFinish() {
          mBtnDelay.setText("延时" + mDelayTime + "秒");
          takePicture();
        }
      }.start();
    }
  }

  • 切换闪光
  /**
   * 闪光标识--自动开启
   */
  private static final int FLASH_ZERO = 0;
  /**
   * 闪光标识--总是开启
   */
  private static final int FLASH_ONE = 1;
  /**
   * 闪光标识--关闭
   */
  private static final int FLASH_TWO = 2;
  /**
   * 切换闪光模式
   */
  private void switchFlash() {
    switch(mFlashMode) {
      case FLASH_ZERO:
        mFlashMode = FLASH_ONE;
        mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        break;
      case FLASH_ONE:
        mFlashMode = FLASH_TWO;
        mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
        break;
      case FLASH_TWO:
        mFlashMode = FLASH_ZERO;
        mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
        // 必须设置
        mCameraCaptureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
        break;
    }
    try {
      mCameraCaptureSession.setRepeatingRequest(mCameraCaptureBuilder.build(), null, mCameraHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  

代码下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,412评论 25 707
  • 这是我第一次读这本书所写的读后感和读书笔记。工作第二年。 读后感 作者在书中写到:During the three...
    一书onebook阅读 782评论 1 1
  • 《小王子》是译本最多的法国文学名著。 这是法国当代一部有名的童话——法国作家圣·埃克苏佩里“为大人...
    沪上剑客阅读 923评论 0 2
  • 人设这个词,最近在娱乐圈的新闻里,比较常见。大概是指一个人想把自己在公众面前塑造成一个什么样的形象,一旦出现什么负...
    牵线木偶娃娃阅读 309评论 2 2
  • 如果你爱我 作者:维吉尼亚·萨提亚 请你爱我之前先爱你自己 爱我的同时也爱着你自己 你若不爱你自己 你便无法来爱我...
    觉知中的帆阅读 150评论 0 0