Android 5.1-手电筒应用小思路(三)
来源:互联网 发布:base笔记软件 编辑:程序博客网 时间:2024/05/21 09:05
前面记录了两篇关于Android 4.4开发 Android手电筒小应用的一些心得,当然只是从上层来做一些简单的处理。
然而随着Android的发展和更新,Android Camera类已被标识为过时的类,官方建议开发者使用Camera2。在Android官方文档中也提到过(Android官方开发指南-Camera(相机)。
在Android5.1之前版本的SDK中,看不到android.hardware.camera2,一般看到的都是android.hardware.camera类。android.hardware.camera在Android4.4的版本就已经过时
了,只不过在Android 4.4 SDK中并没有集成android.hardware.camera2,但是Android工程源码中是有的。
这两者有多大区别呢,下面有图有真相,乍一看,小伙伴们都惊呆了,这差别也太大了。不过,我个人感觉,底层可能差别不会太大,只不过上层的封装方式变了。如果你熟悉Android的代码结构,光看android.hardware.camera2中的各个类名,你都能猜出Camera2 需要通过CAMERA_SERVICE 来使用。
而在CameraManager.java中前面的注释也告诉我们需要通过Context.getSystemService()来获得这个类的一个实例,eg:
CameraManager manager = (CameraManager)mContext.getSystemService(Context.CAMERA_SERVICE);
要通过FLASH来实现手电筒,就要open camera,要使用CameraManager中的openCamera方法:
public void openCamera(String cameraId, final CameraDevice.StateCallback callback, Handler handler)
很惊讶,怎么,openCamera()函数是 void类型。但他确实是这样的。cameraId 通过 getCameraIdList()来获取,此函数返回的是一个数组,并非是需要String 类型。也直接告诉我们,要获得CameraId 还需要做处理。按照正常的情况,一款手机通常有两个Camera,分前Camera和后Camera,这个在android.hardware.camera中就有代码表示(camerainfo):
/** * 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)
1 0
- Android 5.1-手电筒应用小思路(三)
- Android-手电筒应用小思路(一)
- Andriod-手电筒应用小思路(二)
- Android第一个小程序(手电筒)
- Android手电筒(闪光灯)
- Android小项目实践之制作手电筒
- Android 七彩手电筒的实现与应用
- <Android 应用 之路> 简易手电筒
- android资料(闪光灯手电筒)
- Android 手电筒(最强适配版)
- android手电筒
- Android手电筒
- Android手电筒
- android 手电筒
- android手电筒
- android手电筒
- android 手电筒
- Android手电筒
- Visual Studio实用调试技巧
- 精通Nginx基础篇之安装配置
- Cocos Studio和Cocos2d-x版本对应关系
- 第6周 项目4 - 数制转换
- 建立链栈算法库
- Android 5.1-手电筒应用小思路(三)
- C
- dom4j解析XML文件
- 黑马程序员——Java高新技术之枚举
- Oracle RAC 11g 安装测试问题小结(还未测试成功)
- 几个C++ 题目
- 在tableview中用动画效果改变cell的高度
- iOS 修改图片的亮度、对比度、饱和度
- Android的IPC机制——Binder (1)