Android 14 新 API:直接监听截屏操作,不用再观察媒体文件了~

news2025/2/26 19:10:34

android14-base-screenshot
截屏可以说是手机设备最常用的功能了,Android 系统非常重视截屏方面的体验,近几年的更新都不忘去优化这方面的体验。

从一开始仅在通知栏提醒已截屏,到 Android 11 支持在左下角生成截屏缩略图供编辑或分享,再到 Android 12 支持滚动截屏,以及这次的 Android 14 允许 App 直接监听用户的截屏操作。

为打造更加标准的监听截屏体验,Android 14 正式推出了受隐私保护的相关 API。简单来说,该 API 允许 App 以 Activity 为单位注册监听 Callback,当这些 Activity 可见并且被用户截屏的话,系统将回调这些 Callback 并告知用户当前的 App 监听到了截屏操作。

如下是官方提供的效果示例:

需要留意的是:监听截屏 API 并不提供图像数据,意在告诉 App 截屏的时机,你可以选择在这个时机做相应的操作。比如:客服类 App 可以询问用户是否要上传截屏以反馈问题抑或引导用户从相册选择截屏;隐私程度高的 App 则可以提醒用户不要泄露、做好隐私保护等等。

实战

首先要给 App 声明监听截屏的权限: DETECT_SCREEN_CAPTURE

<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />

这个权限是 normal 级别的,无需动态申请,APK 被安装的时候将自动授予。

Allows an application to get notified when a screen capture of its windows is attempted.

Protection level: normal

之后的写法比较简单,即在需要监听截屏的 Activity 里注册回调:

  1. 创建 ScreenCaptureCallback 的实例,并在 onScreenCapture() 实现里添加所需逻辑,比如此处为弹出警告 Dialog:
    class ScreenShotActivity : AppCompatActivity() {
        private val screenCaptureCallback = ScreenCaptureCallback {
            Log.d("ScreenShot", "onScreenCaptured()", Throwable())
    
            AlertDialog.Builder(this)
                .setMessage("You have taken a screenshot...")
                .setTitle("Warning")
                .show()
        }
        ...
    }
  1. 接着,在该 Activity 的 onStart() 方法里注册上述的 ScreenCaptureCallback 实例,需要指定该回调的执行线程 Executor
class ScreenShotActivity : AppCompatActivity() {
    ...
    override fun onStart() {
        super.onStart()

        Log.d("ScreenShot", "onStart() registerScreenCaptureCallback")
        registerScreenCaptureCallback(mainExecutor, screenCaptureCallback)
    }
    ...
}
  1. 记得在 Activity 的 onStop() 里注销该 ScreenCaptureCallback 实例,避免内存 leak:
class ScreenShotActivity : AppCompatActivity() {
    ...
    override fun onStop() {
        super.onStop()

        Log.d("ScreenShot", "onStop() unregisterScreenCaptureCallback")
        unregisterScreenCaptureCallback(screenCaptureCallback)
    }
    ...
}

而后将目标 Activity 启动,通过 log 可以看到已经注册了监听回调,后面就是操作截屏进行验证。

04-05 21:57:53.904  5230  5230 D ScreenShot: onStart() registerScreenCaptureCallback

可是问题来了:笔者手动没有能够运行 Android 14 的真机,运行 14 的是 Pixel 6 模拟器。

要知道模拟器上你是无法直接同时按下 POWER 键+ VOLUME DOWN 按键来完成截屏的,同时 Pixel ROM 的通知面板也没有提供截屏的 UI 入口。

笔者突然想到了用 adb 模拟按键事件,可苦苦搜寻之后发现 input keyevent 仅支持单个 keyevent 的模拟。就在要放弃的时候,我忽然想到另一种 event 模拟办法,就是 sendevent

首先通过搜索和尝试获悉 POWER 键的长按输入办法:

adb shell sendevent /dev/input/event0 1 116 1 && adb shell sendevent /dev/input/event0 0 0 0 && sleep 3 && adb shell sendevent /dev/input/event0 1 116 0 && adb shell sendevent /dev/input/event0 0 0 0

再找到 VOLUME DOWN 键的长按输入办法:

adb shell sendevent /dev/input/event12 1 114 1 && adb shell sendevent /dev/input/event12 0 0 0 && sleep 3 && adb shell sendevent /dev/input/event12 1 114 0 && adb shell sendevent /dev/input/event12 0 0 0

两者一结合即可模拟同时长按 POWER 键+ VOLUME DOWN 按键的操作:

adb shell sendevent /dev/input/event0 1 116 1 && adb shell sendevent /dev/input/event0 0 0 0 && adb shell sendevent /dev/input/event12 1 114 1 && adb shell sendevent /dev/input/event12 0 0 0 && sleep 3 && adb shell sendevent /dev/input/event0 1 116 0 && adb shell sendevent /dev/input/event0 0 0 0 && adb shell sendevent /dev/input/event12 1 114 0 && adb shell sendevent /dev/input/event12 0 0 0

需要留意的是上述命令需要在 root 环境下执行,即 adb root 之后再执行 sendevent 命令,当然如果你有真机就无需这么迂回啦。

成功模拟用户截屏操作之后,如愿看到了截屏的缩略图和系统在屏幕下方给用户 App 监听了当前截屏的 Toast 提醒

以及系统给予当前 App 的截屏操作的回调:

04-05 21:58:04.459  5230  5230 D ScreenShot: onScreenCaptured()

App 也依据回调弹出了代码里拟定的截屏警告 Dialog。

能监听到 adb 等方式发起的截屏吗?

了解 Android 上截屏的朋友会知道,截屏的发起方式有很多种,除了最常用的按键组合外还可以:

  • 代码中使用 DeviceCapture test 框架、MediaProjectionManager、SurfaceControl 发起
  • 调试中使用 adb 命令发起
  • AS 的 logcat 窗口里的 “Screen Capture” 图标、Emulator 窗口的 “Take Screenshot” 菜单

等等。

那这些场景下的截屏操作,14 的方式是否能监听到呢?

答案是否定的,官方予以了明确说明:

In Android 14, the system API only detects a screenshot if the user performs a specific combination of hardware button presses. The API doesn’t detect screenshots that are taken when running test commands related to screenshots, including ADB, or within instrumentation tests that capture the device’s current screen contents.

笔者也实际尝试了下,无论是 ADB 命令还是 AS 的 UI 入口触发的截屏,都没有回调上述的 ScreenCaptureCallback,系统亦没有截屏的提醒。

理由也可想而知,一般用户不会用这样的方式截屏,这种调试场景下、系统场景下的截屏需求甚至不会在屏幕下方展示缩略图,自然没有必要回调监听的 API 了。

原理

Android 14 的源码尚未公开,但可以打印 ScreenCaptureCallback 的堆栈瞥到相关细节:

04-06 22:35:23.593  4627  4627 D ScreenShot: onScreenCaptured()
04-06 22:35:23.593  4627  4627 D ScreenShot: java.lang.Throwable
04-06 22:35:23.593  4627  4627 D ScreenShot:    at eu.thomaskuenneth.textviewhighlightsdemo.ScreenShotActivity.screenCaptureCallback$lambda-0(ScreenShotActivity.kt:13)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at eu.thomaskuenneth.textviewhighlightsdemo.ScreenShotActivity.$r8$lambda$5lHWf6dEQmh2JMn9HXzbeN068DI(Unknown Source:0)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at eu.thomaskuenneth.textviewhighlightsdemo.ScreenShotActivity$$ExternalSyntheticLambda0.onScreenCaptured(Unknown Source:2)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.app.ScreenCaptureCallbackHandler$ScreenCaptureObserver.lambda$onScreenCaptured$0(ScreenCaptureCallbackHandler.java:66)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.app.ScreenCaptureCallbackHandler$ScreenCaptureObserver$$ExternalSyntheticLambda0.run(Unknown Source:2)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Handler.handleCallback(Handler.java:958)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Handler.dispatchMessage(Handler.java:99)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Looper.loopOnce(Looper.java:205)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Looper.loop(Looper.java:294)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.app.ActivityThread.main(ActivityThread.java:8128)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at java.lang.reflect.Method.invoke(Native Method)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:946)

通过上述堆栈 ,再结合 13 的现有截屏逻辑,可以推测下该 Callback 的实现:

  1. SystemUI 的 TakeScreenshotService 在截屏完成之后通知 AMS,AMS 判断当前 Activity 的 ScreenCaptureCallbackHandler 中是否存在 ScreenCaptureObserver
  2. YES 则意味着注册了 ScreenCaptureCallback,便通过 AIDL 告知 App 进程,App 进程内部通过 Handler 告知 ScreenCaptureCallbackHandler 在预设的 Executor 执行 onScreenCaptured() 回调

总结

ScreenCaptureCallback 监听截屏 API 的使用简单、清晰,以后不需要再通过监听媒体文件的变化等逻辑来迂回实现,采用官方的方式去探测用户的截屏操作并按照文件读写的规范去提取文件。

但需要留意 adb、代码、AS 等方式发起的截屏无法通过该 API 监听得到,笔者以为这些不属于用户操作,没有必要纳入到监听范围中。另外,这个监听 API 并不是 Application 级别的,每个目标 Activity 都得注册,所以可以考虑在 BaseActivity 中完成 API 的注册和注销。

相信这个 API 后续亦会扩展到 Jetpack 当中,届时无论是否升级到了 Android 14 都可以尝试切换到官方的监听截屏方式中来。

参考

  • Detect when users take device screenshots
  • DeviceCapture
  • ADB 模拟输入事件总结
  • Android系统截屏的实现分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/427238.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机图形学 | 变换与观察

计算机图形学 | 变换与观察计算机图形学 | 变换与观察6.1 神奇的齐次坐标回顾几何阶段几何变换平移比例旋转对称错切齐次坐标的引入齐次坐标的概念和相关问题基于齐次坐标的变换6.2 三维模型&#xff0c;动起来&#xff01;基本三维变换平移比例旋转对称错切整体比例变换逆变换…

《计算机网络——自顶向下方法》精炼——1.4到1.7

三更灯火五更鸡&#xff0c;努力学习永不止。无惧困难与挑战&#xff0c;砥砺前行向成功。 文章目录引言正文时延排队时延吞吐量协议层次&#xff0c;服务模型&#xff08;重点&#xff09;封装&#xff08;重点&#xff09;网络安全&#xff08;选看&#xff09;恶意软件的分类…

【数据分析与挖掘】数据预处理

目录概述一、数据清洗1.1 缺失值处理1.1.1 拉格朗日插值法1.1.2 牛顿插值法1.2 异常值处理二、数据集成2.1 实体识别2.2 冗余属性识别三、数据变换3.1 简单函数变换3.2 规范化3.3 连续属性离散化3.4 属性构造3.5 小波变换四、数据规约4.1 属性规约4.2 数值规约概述 数据挖掘过…

Spring Boot中使用Redis

目录 1.依赖 2.依赖关系 3.配置 4.RedisTemplate 5.基础操作 6.事务 1.依赖 maven依赖如下&#xff0c;需要说明的是&#xff0c;spring-boot-starter-data-redis里默认是使用lettuce作为redis客户端的驱动&#xff0c;但是lettuce其实用的比较少&#xff0c;我们常用的…

如何在 Web 实现支持虚拟背景的视频会议

前言 众所周知&#xff0c;市面上有比如飞书会议、腾讯会议等实现视频会议功能的应用&#xff0c;而且随着这几年大环境的影响&#xff0c;远程协作办公越来越成为常态&#xff0c;关于视频会议的应用也会越来越多&#xff0c;且在远程办公的沟通协作中对沟通软件的使用要求会…

ARMv8-A非对齐数据访问支持(Alignment support)

目录 1&#xff0c;对齐传输和非对齐传输 2&#xff0c;AArch32 Alignment support 2.1 Instruction alignment 指令对齐 2.2 Unaligned data access 非对齐数据访问 2.3 SCTLR.A Alignment check enable 3&#xff0c;AArch64 Alignment support 3.1 Instruction align…

Text to image论文精读GigaGAN: 生成对抗网络仍然是文本生成图像的可行选择

GigaGAN是Adobe和卡内基梅隆大学学者们提出的一种新的GAN架构&#xff0c;作者设计了一种新的GAN架构&#xff0c;推理速度、合成高分辨率、扩展性都极其有优势&#xff0c;其证明GAN仍然是文本生成图像的可行选择之一。 文章链接&#xff1a;https://arxiv.org/abs/2303.0551…

大数据周会-本周学习内容总结07

目录 01【hadoop】 1.1【编写集群分发脚本xsync】 1.2【集群部署规划】 1.3【Hadoop集群启停脚本】 02【HDFS】 2.1【HDFS的API操作】 03【MapReduce】 3.1【P077- WordCount案例】 3.2【P097-自定义分区案例】 历史总结 01【hadoop】 1.1【编写集群分发脚本xsync】…

【vue3】关于ref、toRef、toRefs那些事

&#x1f609;博主&#xff1a;初映CY的前说(前端领域) &#x1f4d2;本文核心&#xff1a;ref、toRef、toRefs的使用方法 【前言】我们在上一节的学习当中&#xff0c;使用了reactive()函数将vue3中的数据变成响应式的数据&#xff0c;本文中所讲的三个方法也能实现将数据转化…

安全防御之IPsec VPN篇

目录 1.什么是数据认证&#xff0c;有什么用&#xff0c;有哪些实现的技术手段&#xff1f; 2.什么是身份认证&#xff0c;有什么用&#xff0c;有哪些实现的技术手段&#xff1f; 3.什么是VPN技术&#xff1f; 4.VPN技术有哪些分类&#xff1f; 5.IPsec技术能够提供哪些安…

走进小程序【八】微信小程序中使用【Vant组件库】

文章目录&#x1f31f;前言&#x1f31f;Vant介绍&#x1f31f;Vant安装&#x1f31f;npm 支持&#x1f31f;使用Vant&#x1f31f;引入组件&#x1f31f;页面使用组件&#x1f31f;样式覆盖&#x1f31f;介绍&#x1f31f;解除样式隔离&#x1f31f;使用外部样式类&#x1f31…

基于冯洛伊曼拓扑的鲸鱼算法用于滚动轴承的故障诊断研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

【YOLO】YOLOv8实操:环境配置/自定义数据集准备/模型训练/预测

YOLOv8实操&#xff1a;环境配置/自定义数据集准备/模型训练/预测引言1 环境配置2 数据集准备3 模型训练4 模型预测引言 源码链接&#xff1a;https://github.com/ultralytics/ultralytics yolov8和yolov5是同一作者&#xff0c;相比yolov5&#xff0c;yolov8的集成性更好了&a…

C++面向对象丨1. 内存分区模型

Author&#xff1a;AXYZdong 硕士在读 工科男 有一点思考&#xff0c;有一点想法&#xff0c;有一点理性&#xff01; 定个小小目标&#xff0c;努力成为习惯&#xff01;在最美的年华遇见更好的自己&#xff01; CSDNAXYZdong&#xff0c;CSDN首发&#xff0c;AXYZdong原创 唯…

图解NLP模型发展:从RNN到Transformer

图解NLP模型发展&#xff1a;从RNN到Transformer 自然语言处理 (NLP) 是深度学习中一个颇具挑战的问题&#xff0c;与图像识别和计算机视觉问题不同&#xff0c;自然语言本身没有良好的向量或矩阵结构&#xff0c;且原始单词的含义也不像像素值那么确定和容易表示。一般我们需…

【随笔记】Win11、RTX3070、CUDA117的深度学习机器学习环境配置

文章目录一、创建深度学习 Conda 虚拟环境二、安装 Pytorch-Gpu三、安装 PyTorch Geometric四、安装 Sklearn五、Jupyter 配置5.1 将虚拟环境加入内核5.2 插件配置5.3 主题、字体、字号配置假设你已经安装了Anaconda3&#xff08;最新Anaconda3的安装配置及使用教程&#xff08…

里程碑,ChatGPT插件影响几何?

目录插件发布网络浏览器代码解释器平台生态微软魄力总结3月15日OpenAI推出了GPT-4&#xff0c;引起了全球轰动&#xff0c;仅仅过去一周多时间&#xff0c;OpenAI又宣布推出插件功能。如果说ChatGPT是AI的“iPhone时刻”&#xff0c;那么插件就是ChatGPT的“App Store”。超强的…

SpringBoot整合Flink(施耐德PLC物联网信息采集)

SpringBoot整合Flink&#xff08;施耐德PLC物联网信息采集&#xff09;Linux环境安装kafka前情&#xff1a;施耐德PLC设备&#xff08;TM200C16R&#xff09;设置好信息采集程序&#xff0c;连接局域网&#xff0c;SpringBoot订阅MQTT主题&#xff0c;消息转至kafka&#xff0c…

【chatgpt-01】部署学术神器chatgpt_academic

目录1 chatgpt_academic简介2 前置准备3 项目下载/配置4 安装依赖5 项目配置6 运行7 测试实验性功能1 chatgpt_academic简介 chatgpt_academic是一个科研工作专用ChatGPT拓展&#xff0c;特别优化学术Paper润色体验&#xff0c;支持自定义快捷按钮&#xff0c;支持markdown表格…

Jenkins部署与自动化构建

Jenkins笔记 文章目录Jenkins笔记[toc]一、安装Jenkinsdocker 安装 JenkinsJava启动war包直接安装二、配置mavenGit自动构建jar包三、自动化发布到测试服务器运行超时机制数据流重定向编写清理Shell脚本四、构建触发器1. 生成API token2. Jenkins项目配置触发器3. 远程Git仓库配…