Android手电筒制作

Android 手电筒制作

一、SystemUI中手电筒的控制

推荐:Android QuickSetting—手电筒控制

通过手机下拉状态栏,可以找到手电筒图标。也就是说SystemUI中存在控制手电筒的代码。

SystemUI源码路径:

frameworks\base\packages\SystemUI

找到SystemUI中关于对手电筒控制相应类的位置:

\frameworks\base\packages\SystemUI\src\com\android\systemui\qs\tiles\FlashlightTile.java
/** Quick settings tile: Control flashlight **/
public class FlashlightTile extends QSTileImpl<BooleanState> implements
        FlashlightController.FlashlightListener {
 	@Override
    protected void handleClick() {
        if (ActivityManager.isUserAMonkey()) {
            return;
        }
        boolean newState = !mState.value;
        //调用QSTileImpl的refreshState方法,更新下拉状态栏状态
        refreshState(newState);
        //通过FlashlightController设置手电筒开或关
        mFlashlightController.setFlashlight(newState);
    }   
}

FlashlightController 源码位于:

frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\FlashlightController.java
public interface FlashlightController extends CallbackController<FlashlightListener>, Dumpable 

这是一个接口类,具体实现在FlashlightControllerImpl中:

public class FlashlightControllerImpl implements FlashlightController{
	 private final CameraManager mCameraManager;
     public FlashlightControllerImpl(Context context) {
        mContext = context;
        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);

        tryInitCamera();
    }
     private void tryInitCamera() {
        try {
            mCameraId = getCameraId();
        } catch (Throwable e) {
            Log.e(TAG, "Couldn't initialize.", e);
            return;
        }

        if (mCameraId != null) {
            ensureHandler();
            mCameraManager.registerTorchCallback(mTorchCallback, mHandler);
        }
    }
}

初始化了CameraManager,通过相机控制操作手电筒开关。

在setFlashlight方法中控制手电筒开关。

  public void setFlashlight(boolean enabled) {
        boolean pendingError = false;
        synchronized (this) {
            if (mCameraId == null) return;
            if (mFlashlightEnabled != enabled) {
                mFlashlightEnabled = enabled;
                try {
                    //使用setTorchMode方法控制
                    mCameraManager.setTorchMode(mCameraId, enabled);
                } catch (CameraAccessException e) {
                    Log.e(TAG, "Couldn't set torch mode", e);
                    mFlashlightEnabled = false;
                    pendingError = true;
                }
            }
        }
        dispatchModeChanged(mFlashlightEnabled);
        if (pendingError) {
            dispatchError();
        }
    }

二、制作简单手电筒

1、布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <ImageView
        android:id="@+id/open_button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/openbutton"
        />
</LinearLayout>

直接在主方法布局文件中布局,放置一张按钮图片。

2、声明权限

android.permission.FLASHLIGHT
允许访问闪光灯

(不声明权限,好像也行,当然加上最好)

//用于5之前,已过时
<uses-permission android:name="android.hardware.camera" />

3、主要代码

oncreate

private CameraManager mCameraManager = null;
private boolean FlashlightEnable = true;
private static ImageView imageButton;
private boolean imageStatues = true;
private String mCameraId = "0";
private static int count = 0;


@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       //初始化
        initView();
        //获得mCameraManager对象
        this.mCameraManager = (CameraManager) getApplication().getSystemService(Context.CAMERA_SERVICE);
        //获得CameraID,注册手电筒回调
        tryInitCamera();
        //默认开启程序,打开手电筒
        openFlashlight();
        imageButton.setImageResource(R.drawable.opening);
    }

    private void initView() {
        imageButton = findViewById(R.id.open_button);
        imageButton.setOnClickListener(this);
        tryInitCamera();
    }

//获得CameraID,注册手电筒回调
    private void tryInitCamera() {
        try {
            mCameraId = getCameraId();
        } catch (Throwable e) {
            Log.e(TAG, "Couldn't initialize.", e);
            return;
        }
        if (mCameraId != null) {
            mCameraManager.registerTorchCallback(mTorchCallback, null);
        }
    }

    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;
    }
    @Override
    public void onClick(View v) {
        if (imageStatues) {
            closeFlashlight();
            imageButton.setImageResource(R.drawable.openbutton);
        } else {
            openFlashlight();
            imageButton.setImageResource(R.drawable.opening);
        }
        imageStatues = !imageStatues;
    }

此方法中

  1. 给按钮图片赋值,并设置点击事件监听,每次点击切换图片,并打开或关闭手电筒。
  2. 通过getApplication().getSystemService(Context.CAMERA_SERVICE);获得CameraManager对象。
  3. tryInitCamera()方法中,获得CameraID与registerTorchCallback。
  4. 默认点开应用即打开手电筒。(可自定义)

CameraManager对象用于后面对手电筒的开关。

CameraId在此事实上并不需要去获得,直接给一个值即可。

例:private String mCameraId = "0";

TorchCallback:

private final CameraManager.TorchCallback mTorchCallback =
            new CameraManager.TorchCallback() {
                @Override
                public void onTorchModeUnavailable(String cameraId) {
                    FlashlightEnable = false;
                    if (imageStatues) {
                        imageStatues = false;
                        change();
                    }
                }

                @Override
                public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) {
                    super.onTorchModeChanged(cameraId, enabled);
                    if (count++==1){
                        return;
                    }
                    if (FlashlightEnable != enabled) {
                        FlashlightEnable = enabled;
                    }
                    if (imageStatues != enabled) {
                        imageStatues = enabled;
                        change();
                    }
                }
            };

通过TorchCallback监听手电筒是否可用与状态变化。

onTorchModeChanged方法在启动程序时会调用两次,

第一次cameraId是我们的id(获得到为0),enabled是当前手机手电筒状态

第二次cameraId为2,暂未知代表何意,enabled为false,与当前手电筒状态不同步,与cameraId为0的enable无关。

由此,可以设置判断,只有当监听到的是自己的id时,去同步参数。

通过自设change()方法去同步改变应用图片。

private void change() {
        if (imageStatues) {
            imageButton.setImageResource(R.drawable.opening);
        } else {
            imageButton.setImageResource(R.drawable.openbutton);
        }
    }

open&close:

 private void openFlashlight() {
        try {
            if (mCameraManager != null) {
                mCameraManager.setTorchMode(mCameraId, true);
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void closeFlashlight() {
        try {
            if (mCameraManager != null) {
                mCameraManager.setTorchMode(mCameraId, false);
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

主要通过mCameraManager的setTorchMode()方法去控制手电筒状态。

Android 5之前可使用:

 camera = Camera.open();
                Camera.Parameters parameters = camera.getParameters();
                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                camera.setParameters(parameters);
                camera.startPreview();
// 				camera.stopPreview();
//              camera.release();

开启或关闭手电筒。

后记:

如果在打开应用之后,不做任何操作,直接点Recent(显示最近使用应用)页面,在此关掉的话。onDestory()偶尔并不调用。(本机打log查看,大部分时候无onDestory方法log日志)。

这种情况,如果未开启应用前在SystemUI状态栏中打开手电筒,在打开应用不进行任何操作,之后直接在Recent页面,关掉应用,导致手电筒不关闭。

设置应用打开后的默认状态(即开启默认打开或者关闭一次手电筒)后,onDestory()方法正常被调用,上述现象不在出现。

找到另一篇关于onDestory的介绍:

安卓 后台杀死进程,OnDestroy会执行吗?

扩展:

Android使用Camera2 替代过时的Camera API

在Android 5(API 21,Lollipop)以前,获得相机权限只需要在 AndroidManifest.xml文件里面添加权限就可以用了 。5之后的版本, 允许用户单独管理应用的某个权限,打开或者关闭 。使用相机需要判断是否有权限,没有就需要申请权限。

相机的闪光灯,在相机打开后,在外部会变成不可用状态。也就是说,想要使用闪光灯(手电筒用的就是闪光灯),就需要相机是关闭状态。此处不需要去申请权限。

《SystemUI》限制低电量打开手电筒

Camera2 闪光灯梳理

gitee:https://gitee.com/TongYing1652/torch-test

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值