Android 系统手电筒最强适配版
2015-07-21 21:24
441 查看
在做项目的时候,遇到了打开手电筒的功能。本来在网上相应的代码已经很多,便拿过用了。但是在测试阶段发现各种各样的问题。无论是国产的手机,还是三星的手机。并且随着系统的不同,也有着这种各样的差异。
今天就对这个问题进行统一的整理。
一、4.4及其以下:
1、 打开手电筒:
private static Camera camera; public static void flashLight(final Context context) { try { if (camera != null) { camera.release(); camera = null; } camera = Camera.open(); Camera.Parameters param = camera.getParameters(); param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); camera.setParameters(param); camera.setPreviewTexture(new SurfaceTexture(0)); camera.startPreview(); } } catch (Exception e) { e.printStackTrace(); } }
2、关闭手电筒:
public static void closeFlashLight(final Context context) { try { if (camera == null) { camera = Camera.open(); } Camera.Parameters parameters = camera.getParameters(); parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); camera.setParameters(parameters); camera.stopPreview(); camera.release(); camera = null; } } catch (Exception e) { } }
3、其中:
(1)camera.setPreviewTexture(new SurfaceTexture(0)); 这行代码是为了适配三星的手机。
(2)每一次关闭手电筒后,要对camera 进行释放。
二、Android 5.0 系统在Camera 方面做了很大的改动,废弃掉了Camera类。引入了Camera2 、CameraManager,用于管理摄像头,以便于更好的处理多个摄像头的问题。 具体的细节问题,可以去看其源码。
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.CameraDevice.StateCallback; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; import android.util.Log; import android.util.Size; import android.view.Surface; import java.util.ArrayList; /** * Manages the flashlight. */ public class FlashlightController { private static final String TAG = "FlashlightController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final int DISPATCH_ERROR = 0; private static final int DISPATCH_OFF = 1; private static final int DISPATCH_AVAILABILITY_CHANGED = 2; private final CameraManager mCameraManager; private Handler mHandler; private final ArrayList<FlashlightListener> mListeners = new ArrayList<FlashlightListener>(1); private boolean mFlashlightEnabled; private String mCameraId; private boolean mCameraAvailable; private CameraDevice mCameraDevice; private CaptureRequest mFlashlightRequest; private CameraCaptureSession mSession; private SurfaceTexture mSurfaceTexture; private Surface mSurface; public FlashlightController(Context mContext) { mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); initialize(); } public void initialize() { try { mCameraId = getCameraId(); } catch (Throwable e) { LogUtil.e(TAG, "Couldn't initialize.", e); return; } if (mCameraId != null) { ensureHandler(); mCameraManager.registerAvailabilityCallback(mAvailabilityCallback, mHandler); } } 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); } } public synchronized boolean isAvailable() { return mCameraAvailable; } public void addListener(FlashlightListener l) { synchronized (mListeners) { cleanUpListenersLocked(l); mListeners.add(l); } } public void removeListener(FlashlightListener l) { synchronized (mListeners) { cleanUpListenersLocked(l); } } private synchronized void ensureHandler() { if (mHandler == null) { HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mHandler = new Handler(thread.getLooper()); } } private void startDevice() throws CameraAccessException { mCameraManager.openCamera(getCameraId(), new StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraDevice = camera; postUpdateFlashlight(); } @Override public void onDisconnected(CameraDevice camera) { if (mCameraDevice == camera) { dispatchOff(); teardown(); } } @Override public void onError(CameraDevice camera, int error) { LogUtil.e(TAG, "Camera error: camera=" + camera + " error=" + error); if (camera == mCameraDevice || mCameraDevice == null) { handleError(); } } }, mHandler); } private void startSession() 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<Surface>(1); outputs.add(mSurface); mCameraDevice.createCaptureSession(outputs, new android.hardware.camera2.CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { mSession = session; postUpdateFlashlight(); } @Override public void onConfigureFailed(CameraCaptureSession session) { LogUtil.e(TAG, "Configure failed."); if (mSession == null || mSession == session) { handleError(); } } }, 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( "Camera " + cameraId + "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() { ensureHandler(); mHandler.post(mUpdateFlashlightRunnable); } 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 forceDisable) { try { boolean enabled; synchronized (this) { enabled = mFlashlightEnabled && !forceDisable; } if (enabled) { if (mCameraDevice == null) { startDevice(); return; } if (mSession == null) { startSession(); return; } if (mFlashlightRequest == null) { CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest( CameraDevice.TEMPLATE_PREVIEW); builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH); builder.addTarget(mSurface); CaptureRequest request = builder.build(); mSession.capture(request, null, mHandler); mFlashlightRequest = request; } } else { if (mCameraDevice != null) { mCameraDevice.close(); teardown(); } } } catch (Exception e) { LogUtil.e(TAG, "Error in updateFlashlight", e); handleError(); } } private void teardown() { mCameraDevice = null; mSession = null; mFlashlightRequest = null; if (mSurface != null) { mSurface.release(); mSurfaceTexture.release(); } mSurface = null; mSurfaceTexture = null; } private void handleError() { synchronized (this) { mFlashlightEnabled = false; } dispatchError(); dispatchOff(); updateFlashlight(true); } private void dispatchOff() { dispatchListeners(DISPATCH_OFF, false); } private void dispatchError() { dispatchListeners(DISPATCH_ERROR, false); } private void dispatchAvailabilityChanged(boolean available) { dispatchListeners(DISPATCH_AVAILABILITY_CHANGED, available); } private void dispatchListeners(int message, boolean argument) { synchronized (mListeners) { final int N = mListeners.size(); boolean cleanup = false; for (int i = 0; i < N; i++) { FlashlightListener l = mListeners.get(i); if (l != null) { if (message == DISPATCH_ERROR) { l.onFlashlightError(); } else if (message == DISPATCH_OFF) { l.onFlashlightOff(); } else if (message == DISPATCH_AVAILABILITY_CHANGED) { l.onFlashlightAvailabilityChanged(argument); } } else { cleanup = true; } } if (cleanup) { cleanUpListenersLocked(null); } } } private void cleanUpListenersLocked(FlashlightListener listener) { for (int i = mListeners.size() - 1; i >= 0; i--) { FlashlightListener found = mListeners.get(i); if (found == null || found == listener) { mListeners.remove(i); } } } 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; } updateFlashlight(true); dispatchOff(); } }; private final CameraManager.AvailabilityCallback mAvailabilityCallback = new CameraManager.AvailabilityCallback() { @Override public void onCameraAvailable(String cameraId) { if (DEBUG) LogUtil.d(TAG, "onCameraAvailable(" + cameraId + ")"); if (cameraId.equals(mCameraId)) { setCameraAvailable(true); } } @Override public void onCameraUnavailable(String cameraId) { if (DEBUG) LogUtil.d(TAG, "onCameraUnavailable(" + cameraId + ")"); if (cameraId.equals(mCameraId)) { setCameraAvailable(false); } } private void setCameraAvailable(boolean available) { boolean changed; synchronized (FlashlightController.this) { changed = mCameraAvailable != available; mCameraAvailable = available; } if (changed) { if (DEBUG) LogUtil.d(TAG, "dispatchAvailabilityChanged(" + available + ")"); dispatchAvailabilityChanged(available); } } }; public interface FlashlightListener { void onFlashlightOff(); void onFlashlightError(); void onFlashlightAvailabilityChanged(boolean available); } }
以上是FlashlightController 类。
打开手电筒:
FlashlightController .setFlashlight(true);
关闭手电筒:
FlashlightController .killFlashlight();
仅仅是这个两个方法就可以解决问题。由于5.0系统自己实现的手电筒的功能。所以FlashlightController 这个类便是来自于5.0系统的源码。改动的地方很小。
三、
以上便可以解决手电筒的问题了。但是在实际测试过程中还是有一些问题:
1、在三星拥有5.0系统的手机上,需要用一中的方法,才可以。
2、一些手机在长时间打开手电筒后,闪光灯会自动关闭。例如魅族,Nexus。除非重启手机,否则摄像头便不好用了。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories