/**
* The facing of the camera is opposite to that of the screen.
*/
public static final int CAMERA_FACING_BACK = 0;
/**
* The facing of the camera is the same as that of the screen.
*/
public static final int CAMERA_FACING_FRONT = 1;
而后camera通常才有闪光灯的功能。所以就有必要对CameraId数组进行循环查询各个Camera的功能特性。CameraManager类中的getCameraCharacteristics(String cameraId)函数正好满足需要,此函数的说明告诉我们,此函数查询对应ID camera的功能,返回CameraCharacteristics 类型的东东。于是大胆的在CameraCharacteristics.java中找FLASH相关的代码:FLASH_INFO_AVAILABLE,通过这个可判断有flash特性的camera ID。 为什么openCamera()函数返回的是void类型,且看此函数的第二个参数,是一个callback。CameraDevice.StateCallback 是一个抽象类。在代码中也必须new 此类,来实现此类中的抽象方法。此类中也说明,必须实现此抽象类的onOpened(CameraDevice camera)抽象方法。虽然没有函数体,但是通过它的说明可以了解道,当它被调用的时候,说明camera device 可以使用,所以openCamera并没有返回我们需要的camera,而在这个函数被调用以后,我们就可以获得camera device,也就打开了cameara。 成功获得camera devices以后,就要去设置FLAHS的MODE,而android.hardware.camera2设置Flash mode的方式,跟之前截然不同,之前是通过设置Parameters,android.hardware.camera2 则是通过设置一组键值对来实现。刚开始我也不知道怎么下手,在通过大致了解CameraMetadata 和 CaptureRequest 两个类的源码以后,才发现是以键值对的形式去设置,两个类中都有说明,而且遥相呼应,不难理解。设置Flash mode的大致代码如下:
CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW);
builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
当然,android.hardware.camera 在Android 5.1还是可以使用的。只不过我在实验的过程中碰到一个奇怪的事情,使用android.hardware.camera实现的手电筒分别在Android4.4 和Android 5.1手机上使用,如果手电筒的代码中没有setPreviewTexture(),那么这个手电筒在Android4.4上可以点亮闪光灯,在Android 5.1不能点亮闪光灯。 最后贴点代码,以作纪念!
package com.example.richtorch;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.os.PowerManager;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;
public class TorchActivity extends Activity{
private ImageView mTorImageView;
private boolean torchState;
private static PowerManager.WakeLock wakeLock = null;
private FlashlightManager mFlashlightController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.torch_activity);
mTorImageView = (ImageView) findViewById(R.id.imageview_torchlight);
//we must keep the phone's cpu working after openning flash light.
//if don't do this, the phone maybe crash and reboot.
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "RichTorch");
if(null != wakeLock){
wakeLock.acquire();
}
mFlashlightController = new FlashlightManager(this);
mTorImageView.setTag(false);
torchState = false;
}
public void onClick_Flashlight(View view){
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
Toast.makeText(this, "Sorry! your phone hasn't flash light!", Toast.LENGTH_LONG).show();
return;
}
mFlashlightController.setFlashlight(!getTorchStatus());
torchImageControl(!getTorchStatus());
setTorchStatus(!getTorchStatus());
}
private void torchImageControl(boolean viewTag){
if(viewTag){
TransitionDrawable openStateDrawable = (TransitionDrawable) mTorImageView.getDrawable();
openStateDrawable.reverseTransition(200);
mTorImageView.setTag(true);
}else{
TransitionDrawable closeStateDrawable = (TransitionDrawable)mTorImageView.getDrawable();
closeStateDrawable.reverseTransition(200);
mTorImageView.setTag(false);
}
}
@Override
protected void onPause() {
super.onPause();
if(null != wakeLock){
wakeLock.release();
wakeLock = null;
}
}
@Override
protected void onResume() {
super.onResume();
if(null == mFlashlightController){
mFlashlightController = new FlashlightManager(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mFlashlightController != null){
mFlashlightController.killFlashlight();
mFlashlightController = null;
}
}
private boolean getTorchStatus(){
return torchState;
}
private void setTorchStatus(boolean state){
torchState = state;
}
}
package com.example.richtorch;
import android.annotation.TargetApi;
import android.content.Context;
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.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.util.Size;
import android.view.Surface;
import android.widget.Toast;
import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class FlashlightManager {
private static final String TAG = "FlashlightManager";
private final CameraManager mCameraManager;
private Handler mHandler;
private boolean mFlashlightEnabled;
private String mCameraId;
private CameraDevice mCameraDevice;
private CaptureRequest mFlashlightRequest;
private CaptureRequest.Builder mBuilder;
private CameraCaptureSession mSession;
private SurfaceTexture mSurfaceTexture;
private Surface mSurface;
private Context mContext;
public FlashlightManager(Context context) {
mContext = context;
mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
init();
}
public void init() {
try {
mCameraId = getCameraId();
} catch (Throwable e) {
return;
}
if (mCameraId != null) {
startHandler();
}
}
private void showErrorMsg(){
Toast.makeText(mContext, "don't control camera devices", Toast.LENGTH_LONG).show();
}
public synchronized void setFlashlight(boolean enabled) {
if (mFlashlightEnabled != enabled) {
mFlashlightEnabled = enabled;
postUpdateFlashlight();
}
}
public void killFlashlight() {
boolean enabled;
synchronized (this) {
enabled = mFlashlightEnabled;
}
if (enabled) {
mHandler.post(mKillFlashlightRunnable);
}
}
private synchronized void startHandler() {
if (mHandler == null) {
HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mHandler = new Handler(thread.getLooper());
}
}
private void openCameraDevice() throws CameraAccessException {
mCameraManager.openCamera(getCameraId(), mStateCallback, mHandler);
}
private void openCameraSession() throws CameraAccessException {
mSurfaceTexture = new SurfaceTexture(0, false);
Size size = getSmallestSize(mCameraDevice.getId());
mSurfaceTexture.setDefaultBufferSize(size.getWidth(), size.getHeight());
mSurface = new Surface(mSurfaceTexture);
ArrayList<Surface> outputs = new ArrayList<>(1);
outputs.add(mSurface);
mCameraDevice.createCaptureSession(outputs, mSessionStateCallback, mHandler);
}
private Size getSmallestSize(String cameraId) throws CameraAccessException {
Size[] outputSizes = mCameraManager.getCameraCharacteristics(cameraId)
.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(SurfaceTexture.class);
if (outputSizes == null || outputSizes.length == 0) {
throw new IllegalStateException(
"doesn't support any outputSize!");
}
Size chosen = outputSizes[0];
for (Size s : outputSizes) {
if (chosen.getWidth() >= s.getWidth() && chosen.getHeight() >= s.getHeight()) {
chosen = s;
}
}
return chosen;
}
private void postUpdateFlashlight() {
startHandler();
mHandler.post(mUpdateFlashlightRunnable);
}
/**
* @author Richard
* @获得有FLAHS功能的Camera ID。
* */
private String getCameraId() throws CameraAccessException {
String[] ids = mCameraManager.getCameraIdList();
for (String id : ids) {
CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id);
Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
if (flashAvailable != null && flashAvailable
&& lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
return id;
}
}
return null;
}
private void updateFlashlight(boolean status) {
try {
boolean enabled;
synchronized (this) {
enabled = mFlashlightEnabled && !status;
if (enabled) {
if (mCameraDevice == null) {
openCameraDevice();
return;
}
if (mSession == null) {
openCameraSession();
return;
}
if (mFlashlightRequest == null) {
CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW);
builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
builder.addTarget(mSurface);
mFlashlightRequest = builder.build();
mSession.capture(mFlashlightRequest, null, mHandler);
}
} else {
releaseResource();
}
}
} catch (CameraAccessException|IllegalStateException|UnsupportedOperationException e) {
showErrorMsg();
}
}
public void releaseResource() {
if(mBuilder != null){
mBuilder.removeTarget(mSurface);
mBuilder = null;
}
if(mCameraDevice != null){
mCameraDevice.close();
mCameraDevice = null;
}
mCameraDevice = null;
mSession = null;
mFlashlightRequest = null;
if (mSurface != null) {
mSurface.release();
mSurfaceTexture.release();
}
mSurface = null;
mSurfaceTexture = null;
}
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCameraDevice = camera;
postUpdateFlashlight();
}
@Override
public void onDisconnected(CameraDevice camera) {
if (mCameraDevice == camera) {
releaseResource();
}
}
@Override
public void onError(CameraDevice camera, int error) {
if (camera == mCameraDevice || mCameraDevice == null) {
showErrorMsg();
}
}
};
private final CameraCaptureSession.StateCallback mSessionStateCallback =
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
if (session.getDevice() == mCameraDevice) {
mSession = session;
} else {
session.close();
}
postUpdateFlashlight();
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
if (mSession == null || mSession == session) {
showErrorMsg();
}
}
};
private final Runnable mUpdateFlashlightRunnable = new Runnable() {
@Override
public void run() {
updateFlashlight(false);
}
};
private final Runnable mKillFlashlightRunnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
mFlashlightEnabled = false;
}
//releaseResource();
updateFlashlight(true);
}
};
}
链接: http://pan.baidu.com/s/1iEZuQ 密码: 1jdq (源码是链接下的RichTorch)