博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
<Android 应用 之路> 简易手电筒
阅读量:6370 次
发布时间:2019-06-23

本文共 9924 字,大约阅读时间需要 33 分钟。

前言

快一个月没有写自己的博客了,由于最近换了工作,换了居住地,所以有一些杂事需要处理,从今天开始恢复正常,不赘述了。进入今天的主题 —– 简易的手电筒。

这个Demo中使用的是比较新的API,M版本之后添加的针对于手电筒的接口。这里使用的是Camera的API2接口,主要使用CameraManager中针对于闪光灯的一些方法,对于Camera API2的接口,后面在涉及相机应用的时候,API1和API2应该都会梳理一下,到时候再仔细的研究一下。


思路

实现一个简单的手电筒,考虑到M版本上新增的接口,可以直接通过setTorchMode来改变闪光灯的状态,实现开关,然后根据当前的闪光灯状态,有回调函数,若其他的应用打开了闪光灯或者是关闭了闪光灯,该应用要作出对应的调整,同时,开启和关闭的过程,需要有明显的用户感知和提示,这就要结合NotificationManager和CameraManager的接口一起实现了。


接口介绍

CameraManager.java(frameworks/base/core/java/android/hardware/camera2)

这里写图片描述

方法 含义
TorchCallback 针对闪光灯的回调
AvailabilityCallback 针对相机是否可用的回调
CameraManager() 构造函数
getCameraIdList() 获取相机的Id
registerAvailabilityCallback() 注册相机是否可用的回调
unregisterAvailabilityCallback() 解除注册
registerTorchCallback() 注册针对闪光灯状态的回调
unregisterTorchCallback() 解除注册
getCameraCharacteristics() 传入参数为相机的id,获取相机的一些参数信息,如支持的预览大小,支持的滤镜等等
openCamera() 传入的参数为相机的id和状态的回调StateCallback,这个是在CameraDevice中定义的,打开相机操作
setTorchMode() 设置闪光灯的状态

实战代码

1.布局文件

由于是手电筒,布局文件很简单,主布局中只有一个button

activity_custom_button.xml

显示当前闪光灯被占用的自定义Toast布局

busy_toast.xml

2.代码文件

主要就是两个类,一个是主Activity,一个就是用来执行notification的pendingintent的广播接收器

FlashActivity.java

package mraz.com.custombutton;import android.annotation.TargetApi;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.Context;import android.content.Intent;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.hardware.camera2.CameraAccessException;import android.hardware.camera2.CameraManager;import android.os.Build;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.app.NotificationCompat;import android.view.Gravity;import android.view.View;import android.widget.Button;import android.widget.FrameLayout;import android.widget.Toast;@TargetApi(Build.VERSION_CODES.M)public class FlashActivity extends AppCompatActivity {
public static final String CLOSE_FLASH_ACTION = "android.intent.action.close_flash"; private static final int NOTIFICATIONID = 0; private Button btFlash; private boolean mIsFlashOn = false; private CameraManager cameraManager = null; private String[] mCameraIds; private Notification mFlashOnNotification = null; private NotificationManager notificationManager = null; private boolean isFlashAvailbale = true; private FrameLayout mContentPanel = null; //闪光灯状态变化的回调 private CameraManager.TorchCallback torchCallback = new CameraManager.TorchCallback() { @Override public void onTorchModeUnavailable(String cameraId) { super.onTorchModeUnavailable(cameraId); //onTorchModeUnavailable 当前闪光灯不可用,如果当前闪光处于打开状态,则关闭它,并且对应的标志位 if (cameraId.equals(mCameraIds[0]) && mIsFlashOn) { reverseFlashState(); } isFlashAvailbale = false; System.out.println("cameraId = " + cameraId + " onTorchModeUnavailable"); } @Override public void onTorchModeChanged(String cameraId, boolean enabled) { super.onTorchModeChanged(cameraId, enabled); //onTorchModeChanged 闪光灯状态变化回调 enabled=false 闪光灯关闭 //enabled=true 闪光灯已经开启 //通过这个回调设置标志位,如果当前闪光灯开着但是收到了闪光灯已经被关闭的回调,则改变对应的状态 isFlashAvailbale = true; System.out.println("cameraid = " + cameraId + " enabled = " + enabled + " misFlashOn = " + mIsFlashOn); if (cameraId.equals(mCameraIds[0]) && enabled == false && mIsFlashOn) { reverseFlashState(); } System.out.println("cameraId = " + cameraId + " onTorchModeChanged enabled = " + enabled); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_button); //闪光灯开关按钮 btFlash = (Button) findViewById(R.id.bt_flash); //整个布局 mContentPanel = (FrameLayout) findViewById(R.id.flash_content); btFlash.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { reverseFlashState(); } }); //根据当前闪光灯装填设置一下UI界面的颜色 changeFlashUi(mIsFlashOn); } //flash状态翻转 private void reverseFlashState() { //如果当前Flash 处于unavailable状态,说明当前闪光灯被占用,无法使用 if (!isFlashAvailbale) { //显示当前闪光灯被占用的提示 showFlashBusy(); return; } changeFlashState(mIsFlashOn);//开->关 关->开 mIsFlashOn = !mIsFlashOn;//标志位装换 changeFlashUi(mIsFlashOn);//界面UI切换,这里主要就是为了突出闪光灯开关的状态不同 applyNotification(mIsFlashOn);//闪光灯开启的提示显示和消除 } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void applyNotification(boolean isFlashOn) { if (!isFlashOn) { dismissNotification(); return; } if (mFlashOnNotification != null && notificationManager != null) { notificationManager.notify(NOTIFICATIONID, mFlashOnNotification); } } @Override protected void onResume() { super.onResume(); cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE); notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); cameraManager.registerTorchCallback(torchCallback, null);//注册回调 getCameraList();//获取当前手机的摄像头个数 generateNotify();//生成需要显示的提示,方便后面显示 } @Override protected void onDestroy() { super.onDestroy(); cameraManager.unregisterTorchCallback(torchCallback);//ondestory的时候解除回调 } @TargetApi(Build.VERSION_CODES.M) //只有M版本的手机可以使用这个方法 private void changeFlashState(boolean isFlashOn) { if (cameraManager != null && mCameraIds != null) { try { cameraManager.setTorchMode(mCameraIds[0], !isFlashOn); } catch (CameraAccessException e) { e.printStackTrace(); } } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) //只有L版本的收集可以使用这个方法 private void getCameraList() { if (cameraManager != null) { try { mCameraIds = cameraManager.getCameraIdList(); } catch (CameraAccessException e) { e.printStackTrace(); } } } //按钮的背景图切换 private void changeFlashUi(boolean isFlashOn) { if (isFlashOn) { btFlash.setBackgroundResource(R.drawable.flash_open); } else { btFlash.setBackgroundResource(R.drawable.flash_close); } } //生成notification的大图标 private Bitmap createNotificationLargeIcon(Context c) { Resources res = c.getResources(); int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width); int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height); Bitmap result = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(res, R.mipmap.ic_flash_on_normal), width, height, false); return result; } //生成notification private void generateNotify() { if (mFlashOnNotification != null) return; NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setLargeIcon(createNotificationLargeIcon(this)) .setContentTitle("手电筒已开启") .setContentText("点击可关闭手电筒") .setSmallIcon(R.mipmap.ic_flash_off_normal, 3) .setContentIntent(createCloseFlashPendingIntent()); mFlashOnNotification = builder.build(); } //消除notification private void dismissNotification() { if (notificationManager != null && mFlashOnNotification != null) { notificationManager.cancel(NOTIFICATIONID); } } //创建点击notification对应的PendingIntent private PendingIntent createCloseFlashPendingIntent() { Intent intent = new Intent(); intent.setClass(this, FlashCloseReceiver.class); intent.setAction(CLOSE_FLASH_ACTION); return PendingIntent.getBroadcast(this, 0, intent, 0); } //显示一个手电筒忙碌的提示 private void showFlashBusy() { View toastContent = getLayoutInflater().inflate(R.layout.busy_toast, null, false); Toast toast = new Toast(this); toast.setView(toastContent); toast.setGravity(Gravity.CENTER, 0, 0); toast.setDuration(Toast.LENGTH_LONG); toast.show(); }}

FlashCloseReceiver.java

package mraz.com.custombutton;import android.annotation.TargetApi;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.hardware.camera2.CameraAccessException;import android.hardware.camera2.CameraManager;import android.os.Build;public class FlashCloseReceiver extends BroadcastReceiver {
CameraManager mCameraManager = null; String[] mCameraIds = null; public FlashCloseReceiver() { } @TargetApi(Build.VERSION_CODES.M) @Override public void onReceive(Context context, Intent intent) { System.out.println("onReceiver"); mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); if (mCameraManager != null) { try { mCameraIds = mCameraManager.getCameraIdList(); } catch (CameraAccessException e) { e.printStackTrace(); } } String action = intent.getAction(); if (action.equals(FlashActivity.CLOSE_FLASH_ACTION)) { if (mCameraManager != null && mCameraIds != null && mCameraIds.length != 0) { try { System.out.println("setTorchMode"); mCameraManager.setTorchMode(mCameraIds[0], false); } catch (CameraAccessException e) { e.printStackTrace(); } } } }}

实际效果图

手电筒关闭状态

这里写图片描述

手电筒开启状态

这里写图片描述

手电筒开启状态提示信息

这里写图片描述


备注

由于开发时间比较短,测试可能不充分,有问题欢迎留言讨论~

转载于:https://www.cnblogs.com/lanzhi/p/6467185.html

你可能感兴趣的文章
沉思录:别人的棺材
查看>>
jersey + spring + mybatis + redis项目搭建
查看>>
PAT 1006 部分正确_另一种解法
查看>>
在Keil环境下使用JLink实现printf输出重定向至debug窗口
查看>>
postgres的\d命令不显示全部的用户表
查看>>
poj 3468 A Simple Problem with Integers
查看>>
OOA/OOD/OOP细讲
查看>>
Tomcat 系统架构与设计模式_ 设计模式分析
查看>>
本地串口TCP/IP 映射到远端串口
查看>>
锁机制探究
查看>>
硬盘直接引导启动Manjaro Linux iso
查看>>
CodeSmith代码生成工具介绍
查看>>
几个常用且免费的接口
查看>>
jQuery文件上传插件 Uploadify更改错误提示的弹出框
查看>>
RHEL6下Apache与Tomcat整合
查看>>
Heartbeat+DRBD+MFS高可用
查看>>
要感谢那些曾经慢待你的人
查看>>
常见的global cache等待事件
查看>>
第 7 章 多主机管理 - 047 - 管理 Machine
查看>>
CentOS5和6的系统启动流程
查看>>