目录

背景

方案设计

主要实现

待完善

完整源码

背景

公司安全政策限制,上班期间不能拍照/录像。虽然已经差不多养成习惯,但老虎保不住也有打盹的时候,曾经有一次就差点违规。所以期望有一款app能代为管理,上班期间拍照/录像的时候会自动提示或者功能不可用,下班期间自动放开限制。

方案设计

可选方案1:接收NEW_PICTURE事件广播

首先自然而然地想到广播,相机拍照时系统会发出action为com.android.camera.NEW_PICTURE的广播,可以创建一个接收器在接收到这个广播时提示不允许拍照。AndroidManifest.xml文件中对广播接收器做静态注册,如下:

<!-- AndroidManifest.xml -->
​
<receiverandroid:name=".CameraEventReceiver"android:enabled="true"><intent-filter><action android:name="com.android.camera.NEW_PICTURE" /></intent-filter>
</receiver>

问题是,这里的NEW_PICTURE是点击拍照按钮产生的广播事件,找了一圈没有找到打开相机产生的广播事件,这时拍照已成既定违规事实了,不能起到事前/事中提醒或禁止作用,不符合要求。

可选方案2:CameraManager的onCameraUnavailable回调

CameraManager 是系统服务之一,专门用于 检测打开相机以及获取相机设备特性。可以使用onCameraUnavailable回调函数在相机被占用时(意味着打开了相机)进行提醒。核心代码如下:

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
manager.registerAvailabilityCallback(new CameraManager.AvailabilityCallback() {@Overridepublic void onCameraUnavailable(String cameraId) {super.onCameraUnavailable(cameraId);Log.i(TAG, "camera unavailable");// 提示相机不可用等弹框
}

功能上没问题,只是要保证服务一直在后台运行,才能在需要的时候提醒用户。其实安装这个App只是起到辅助提醒作用,真正需要提醒用户的概率很小很小,一直让App在后台运行太浪费手机资源。而且这个提醒功能只能做到事中提醒,能不能直接把相机直接禁用掉,事前防范,让用户没有犯错的机会呢。

可选方案3(最终方案):Android Device Administration API禁用相机功能

Android Device Administration API 是Android 用来提供企业应用支持的,通过API可以在系统级别提供密码管理、停用相机等设备管理功能。通过调用API,打开相机时给予以下错误提示:

再配合闹钟(AlarmManager)实现定时开关,这恰恰就是我想要的,完美!

主要实现

1. 启用Device Administration API (MainActivity)

DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName deviceAdmin = new ComponentName(this, MyDeviceAdminReceiver.class);
​
if (!(devicePolicyManager.isAdminActive(deviceAdmin))) {// 启用Device Admin APIstartActivateDeviceAdminActivityForResult();
} else {CameraUtil.blockOrUnblockCameraNow(this, amStartWorkTime, amStopWorkTime, pmStartWorkTime, pmStopWorkTime);
}
​
private void startActivateDeviceAdminActivityForResult() {Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,deviceAdmin);intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,getString(R.string.admin_explanation));startActivityForResult(intent, REQUEST_ENABLE);
}

2. 根据当前是否在工作时间段,发送启用/禁用相机广播

public class CameraUtil {public static void blockOrUnblockCameraNow(Context context, int amStartWorkTime, int amStopWorkTime, int pmStartWorkTime, int pmStopWorkTime) {Intent intent = new Intent();intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);intent.setComponent(new ComponentName("com.aniu.cameramanager","com.aniu.cameramanager.AlarmReceiver"));if (WorkTime.isNowWorkTime(amStartWorkTime, amStopWorkTime, pmStartWorkTime, pmStopWorkTime)) {context.sendBroadcast(intent.setAction("ACTION_BLOCK_CAMERA"));} else {context.sendBroadcast(intent.setAction("ACTION_UNBLOCK_CAMERA"));}}
}

3. 根据广播启用/禁用相机 ,并设置下一次的闹钟 (AlarmReceiver)

public void onReceive(Context context, Intent intent) {if (action.equals("ACTION_BLOCK_CAMERA")) {devicePolicyManager.setCameraDisabled(deviceAdmin, true);Log.i(TAG, "禁用相机成功, action: " + action);
​// 设置下一次的闹钟setCameraAlarm(context, getNextCameraAlarm());} else if (action.equals("ACTION_UNBLOCK_CAMERA")) {devicePolicyManager.setCameraDisabled(deviceAdmin, false);Log.i(TAG, "启用相机成功, action: " + action);
​// 设置下一次的闹钟setCameraAlarm(context, getNextCameraAlarm());}
}
​
private void setCameraAlarm(Context context, Alarm alarm) {Intent intent = new Intent(context, alarm.getAlarmReceiver());intent.setAction(alarm.getAction());intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);intent.setComponent(new ComponentName("com.aniu.cameramanager","com.aniu.cameramanager.AlarmReceiver"));PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 999, intent, 0);Calendar calendar = alarm.getCalendar();
​AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);Log.i(TAG, "设置闹钟成功: " + alarm.getCalendar().getTime() + " " + alarm.getAction());
}

实现过程中的坑点和对应处理

  1. 原计划使用AlarmManager的循环闹钟,但目前(2021-6-8)情况下循环闹钟的事件都是不精确的,在华为畅享9(我的主力测试机)上实测差几分钟/几十分钟的情况都存在,所以使用了单个闹钟AlarmManager.setExactAndAllowWhileIdle方法,低功耗下也可以准确执行。方法的第一个参数使用AlarmManager.RTC_WAKEUP,即以系统时间为参照。

  2. 广播定向发送

    在很多手机上应用发送广播需要申请权限或者特殊处理,不然会接收不到广播,这里设置成了定向广播:

    intent.setComponent(new ComponentName("com.aniu.cameramanager","com.aniu.cameramanager.AlarmReceiver"));
  3. 重启处理

    手机重启后需要让应用保持运行,需要在AlarmReceiver中同时监听开机事件。

    if (action.equals("android.intent.action.BOOT_COMPLETED")) {Log.i(TAG, "监听到重启完成事件, action: " + action);
    ​// 重启后根据当前时间段禁用/启用相机CameraUtil.blockOrUnblockCameraNow(context, amStartWorkTime, amStopWorkTime, pmStartWorkTime, pmStopWorkTime);
    } 

    同时在manifest文件中receiver的intent-filter中增加action android:name="android.intent.action.BOOT_COMPLETED" 。

  4. 保持后台运行

    如果不把应用设置成可后台运行,监听开机事件拉起receiver后很快应用进程就会被系统杀掉,需要提供入口或引导用户设置应用保持后台运行。

  5. 防止被意外强行终止

    很多手机用户喜欢清理最近使用的应用,这里在manifest文件中设置android:excludeFromRecents="true"属性来规避。

待完善

增加临时启用相机入口

虽然程序中增加了当天是否为工作日的判断,节假日不会去停用相机,但如果用户休假,那在原工作时间段内相机还是会停用,导致用户没办法使用相机。需要在提示用户相机被停用的界面增加临时启用相机入口,不妨碍用户正常使用相机。

目前还不知道怎么修改这个界面,在stackoverflow上面提了问题,还没人回复。

完整源码

https://gitee.com/teng-aniu/CemaraManager

工作时段禁用相机功能的Android App设计与实现相关推荐

  1. android app 设计,Android app 设计小结

    Android app设计小结 刚开始做android UI设计和切图的时候,看了好多教程和文章,最后自己总结一下,希望能帮到大家. 一.各屏幕适配--不通的dpi及屏幕尺寸 1.专用词 dpi(像素 ...

  2. 安卓app设计规范整理和Android APP设计篇

    安卓app设计规范整理和Android APP设计篇 发布于: 2014 年 8 月 24 日 by admin 随着安卓智能手机不停的更新换代.安卓手机系统越来越完美,屏幕尺寸也越来越大啦!比如最近 ...

  3. Android App设计架构

    对Android App程序进行架构设计的原因,归根到底是为了提高生产力.通过架构设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一 ...

  4. 基于TensorFlow2.3.0的花卉识别Android APP设计

    一.前言 本设计为基于TensorFlow2.3.0的花卉识别Android APP.TensorFlow2.3.0的API简单易用,训练好后模型导出tflite格式供Anroid APP使用. 开发 ...

  5. 安卓app设计规范整理和Android APP设计篇(转)

    随着安卓智能手机不停的更新换代.安卓手机系统越来越完美,屏幕尺寸也越来越大啦!比如最近小米的miui 6的发布和魅族手机系统的更新等等. 以小米MIUI6的安卓手机来说,MIUI6进行了全新设计,坚持 ...

  6. 安卓app设计规范整理和Android APP设计

    随着安卓智能手机不停的更新换代.安卓手机系统越来越完美,屏幕尺寸也越来越大啦!比如最近小米的miui 6的发布和魅族手机系统的更新等等. 以小米MIUI6的安卓手机来说,MIUI6进行了全新设计,坚持 ...

  7. android网购功能,网购Android App购物车点击动画实现详解

    在做网购APP时,很多的app在点击购物车时都有一个图片动画效果,比较形象,我目前做的项目也涉及到了,把我使用的方法做个笔记: 先看一个简单的截图: 我们在点击列表中带+号的购物车时,会有一个图片多点 ...

  8. Android App设计小结

  9. php android 微信支付,Android_Android实现微信支付功能,开发Android APP微信支付功能, - phpStudy...

    Android实现微信支付功能 开发Android APP微信支付功能,需要完成三个步骤:第一步生成预支付订单.第二步生成微信支付参数.第三步调起微信APP支付.除了需要审核通过的APP应用外,还需要 ...

最新文章

  1. python读取文件r_python read文件的r和rb的区别
  2. R语言dplyr包distinct函数去除重复数据行实战
  3. 《机器人操作系统ROS原理与应用》——1.1 宏观
  4. 大话算法-排序-归并排序
  5. SpringMVC——Spring中的DispatcherServlet怎么工作?
  6. javaIo流实际应用
  7. 简单计算机app inventor,app inventor计算器
  8. SAX EntityResolver 的作用
  9. java类包装器有什么用_Java中的包装器类
  10. 硬盘数据恢复的神器有哪些
  11. 微信小程序网易云音乐获取视频列表数据(需要登录获取携带cookie)
  12. php解压7z,linux解压7z文件命令
  13. 机器学习实战(基于scikit-learn和TensorFlow)学习心得(5)--stratified sampling
  14. 直播带货app源码,实现直播连麦和PK
  15. 分子动力学理论篇(1)——牛顿力学、哈密顿动力学和相空间
  16. matlab调整文字方向,MATLAB改变ylabel文字方向以及截边
  17. 【AI理论学习】多模态介绍及当前研究方向
  18. Respond 的响应式代码阅读
  19. c# picturebox 刷新_c# – 更新PictureBox时可能导致ArgumentException的原因是什么?
  20. 万字长文,小学弟熬夜肝了这份腾讯面试攻略

热门文章

  1. c#常见的正则表达式
  2. 快速生成ppt的新方法
  3. 基于腾讯优图实现二代身份证识别
  4. 百度网盘回应在 APP Store 下架;阿里云发布 AI 助手「通义听悟」;SQL:2023 正式发布|极客头条
  5. 你知道程序都是怎么处理时区问题的么?
  6. 201671030127赵津莹 《英文文本统计分析》结对项目报告
  7. ios android gpu,流畅秒杀iOS Android 4.0 GPU加速测试
  8. python中使用np.array()将list转换成Array的坑
  9. Android花样loading进度条(四)-渐变色环形进度条
  10. Linux下普通用户与超级用户的切换