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
原创粉丝点击