6946 字
35 分钟
为你的 Android 设备补齐注视不熄屏功能 —— GazeKeep 使用指南与原理解析

为你的 Android 设备补齐注视保亮功能 —— GazeKeep 使用指南与原理解析#

先说设计边界与限制#

在进入具体使用与实现之前,先明确 GazeKeep 的能力边界与前提条件:

  1. 设备与系统门槛:Android 8.0(API 26)及以上版本,硬件具备正常可用的前置摄像头。
  2. 适用场景定位:专注于静态、低频交互的场景(如长文阅读、背单词、对照代码/文档、厨房看菜谱等)。解决的是“双手不方便触屏时屏幕频频息屏”的痛点。
  3. 红线与不做的事:
    • 不做人脸注册与身份认证(不关心你是谁);
    • 不追踪视线在屏幕上的具体坐标点,不做眼控滚动;
    • 不做持续后台录像;
    • 彻底不申请网络权限,不依赖任何云端服务。
  4. 判定原则:「看不清就正常熄屏,绝不盲目常亮」。遇到暗光环境、侧脸、闭眼打盹、视线离开屏幕、画面中有多人干扰或前置相机被占用时,GazeKeep 会果断放行,让系统按时进入休眠。

一、为什么要做这个项目#

在日常使用移动设备时,很多朋友大概率都遇到过这样的两难矛盾:

在手机上看长篇技术博客或小说,正沉浸在思路中,十几秒没摸屏幕,屏幕突然变暗并随即熄灭,不得不重新点亮并指纹解锁;又或者在厨房学做菜,双手沾满水渍或油污,想瞄一眼下一步调料克数,手机却已经黑屏了。

为了避免频繁息屏,很多人会去系统设置里把休眠时间调到 5 分钟、10 分钟甚至“永不息屏”。但一旦晚上躺在床上看手机不小心睡着,或者有事离开工位,屏幕就会常亮一整晚。这不仅会导致第二天醒来手机严重发热、电量耗尽,长期下来对 OLED 屏幕更是存在不可逆的灼伤(烧屏)隐患。

「短超时烦人,长超时怕睡着」,这是绝大多数用户在没有特定传感器辅助下的真实困境。

近几年各主流手机厂商的新款旗舰设备,已经在系统层集成了基于前置传感器或 AI 视觉的屏幕注视检测(如华为的「智感不熄屏」、荣耀的「注视屏幕不熄屏」等)。这些原生功能深度整合在系统的电源管理服务(PowerManagerService)中:平时完全不占用摄像头,仅在屏幕即将熄灭的倒计时阶段采样几帧。只要用户还在看着屏幕,就重置息屏计时器;一旦用户转头或离开,屏幕按时休眠,体验非常无感舒适。

然而,大量依然堪用的老旧 Android 设备、千元机、备用平板,以及刷入了原生 AOSP、LineageOS 等第三方类原生 ROM 的设备,厂商并不会为其适配或下放此类系统级特性。许多旧设备屏幕依然通透、性能依然过剩,却因为缺少这项体验,被丢在抽屉里吃灰,或者在使用时频繁让人抓狂。

为了让旧设备也能拥有媲美新旗舰的注视保亮体验,我开发并开源了 GazeKeep(注视保亮)。

IceTeacher
/
GazeKeep
Waiting for api.github.com...
00K
0K
0K
Waiting...

它的初衷非常纯粹:为没有提供系统级注视保亮功能的 Android 设备,补齐安全、无感且可媲美系统原生体验的注视保亮能力,让旧设备也能更省心、更好地被使用。

二、这个项目能做什么#

GazeKeep 是一款专为 Android 打造的端侧离线注视保亮工具,其设计核心可以用八个字概括:目光所及,屏幕常明。

2.1 核心特性与架构思路#

  1. 临近熄屏按需短时采样,平时零占用:
    传统第三方防熄屏软件往往通过后台常驻唤醒锁(WakeLock)或者常开摄像头进行实时人脸追踪,不仅发热量巨大、电量如瀑布般消耗,系统状态栏还会一直挂着刺眼的绿色相机隐私指示灯。
    GazeKeep 借鉴了系统底层的设计思路:平时完全静默、不打开相机;仅在系统临近降亮或熄屏前的最后 3~5 秒,以微秒级延迟快速唤醒前置摄像头采样 1~3 帧画面并立即交给端侧模型推理。确认注视后重置系统息屏倒计时,并在几十毫秒内迅速关闭释放相机硬件。
  2. 端侧离线推理,绝不盲目常亮:
    检测算法基于 Google ML Kit Face Mesh 的端侧离线模型进行轻量化剪裁,所有图像数据均在当前 App 内存中同步闭环处理。
    对于光线不足、侧脸角度过大、闭眼打盹、视线离开屏幕(“未注视屏幕”)、识别置信度不足(“这次没看清”)、画面中出现多人干扰,或摄像头正在被微信扫码、系统相机独占等情况,GazeKeep 会果断放弃干预,让系统像往常一样准时黑屏。
  3. 单次最长保亮时间保护(防烧屏安全阀):
    为了防止极特殊姿态下被误判造成无限期保亮,系统内置了单次最长保亮时间阈值(默认为 30 分钟,支持自定义时长或关闭)。只要累计连续保亮达到设定时长,就会强制释放保亮能力让屏幕熄灭一次。
  4. 三种后端分级适配不同玩机条件:
    不同用户的搞机基础与设备状态千差万别。GazeKeep 提供了 LSPosed 模块(系统级框架联动)、Shizuku(无线调试/ADB 免 Root 授权)以及 系统无障碍服务(零门槛开箱即用)三种后端方案,支持自动优选与手动锁定。

三、官网项目的前端设计与视觉呈现#

除了 Android 客户端本身,我还为 GazeKeep 设计并搭建了官方网站(gazekeep.rainafter.cn,源码位于仓库 apps/web)。

作为一款主打“安静、无感、原生体验”的工具,官网需要把抽象的底层调度与“目光守护屏幕”的体验具象化传达给访问者。项目基于 Astro 与 Tailwind CSS 搭建,重点实现了动态着色器(Shader)粒子流、高保真真机视差演示以及全站平滑的 View Transitions。

3.1 动态 Shader 粒子流:把“注视与光芒”转化为视觉语言#

在首屏 Hero 区域,静态渐变图缺乏生命力,直接放视频又过于笨重影响加载速度。因此我在背景层编写了一段基于 Three.js / WebGL 的轻量片元着色器(Fragment Shader):

apps/web/src/shaders/gaze-glow.frag
precision highp float;
uniform float uTime;
uniform vec2 uResolution;
uniform vec2 uGazePoint; // 鼠标滑动或默认缓动映射的视线焦点
varying vec2 vUv;
void main() {
vec2 st = (gl_FragCoord.xy * 2.0 - uResolution) / min(uResolution.x, uResolution.y);
vec2 gaze = (uGazePoint * 2.0 - uResolution) / min(uResolution.x, uResolution.y);
// 计算点到注视焦点的欧氏距离与动态光晕扩散
float dist = length(st - gaze);
float pulse = 0.5 + 0.5 * sin(uTime * 1.5 - dist * 4.0);
// 呼吸式微光:营造屏幕被目光唤醒的柔和聚光效果
float glow = smoothstep(1.2, 0.1, dist) * 0.18 + pulse * 0.04;
vec3 baseColor = vec3(0.06, 0.08, 0.12);
vec3 accentColor = vec3(0.24, 0.58, 0.98); // GazeKeep 标志性天青蓝
vec3 color = mix(baseColor, accentColor, glow);
gl_FragColor = vec4(color, 1.0);
}

为了不抢占移动端浏览器的资源,着色器做了两项针对性优化:

  • 视口离开即停:通过 IntersectionObserver 监听 Hero 区域。一旦滚出首屏范围,立即挂起 requestAnimationFrame 渲染循环,GPU 占用降至 0;
  • 明暗主题自适应:Shader 的 Uniform 颜色参数与全站主题状态联动,能够在深邃暗夜蓝与澄澈浅灰之间平滑过渡。
官网首屏动态 Shader 与目光聚光微澜动效(1080P 60FPS 实录)

3.2 高保真真机视差模型:直观演示完整动作周期#

文字描述“息屏前 3 秒快速采样”依然较为抽象。在官网的特性介绍区域,我设计了一个由纯 CSS 与原生 JavaScript 驱动的高保真手机模型(Phone Mockup):

实现方式

真机模型利用 CSS 3D transform: perspective(...) rotateX(...) rotateY(...) 响应鼠标移动产生细腻的视差悬浮效果。访客不需要下载 APK,就能在网页上直观看到“正视屏幕保亮”与“移开视线放行熄屏”的整个完整交互周期。

连续滚动时真机模型与特性卡片的联动演示(1080P 60FPS 实录)

在向下滚动的过程中,真机模型会无缝进入应用白名单管理与设置项调优两大核心特性的演示:

应用列表与白名单定向生效演示(60FPS)
设置项微调与表盘刻度联动演示(60FPS)

3.3 平滑的 View Transitions:无缝的多语言与主题切换#

官网全面接入了 Astro 原生的 View Transitions API:

  1. 全站圆形水波纹遮罩过渡(Theme Reveal):
    点击明暗主题切换按钮时,利用 document.startViewTransition 配合 CSS clip-path: circle(...),以鼠标点击坐标为中心向外扩散铺开新主题色彩;
  2. 中英双语文档原地过渡:
    为导航头、文字主容器与代码块配置独立的 view-transition-name,在 /zh/ 与 /en/ 之间切换语言时,排版不会出现白屏刷新,而是原地平滑淡入淡出,保持阅读节奏连贯。
深色 / 浅色模式切换时以点击点为中心扩散的水波纹过渡(1080P 60FPS 实录)

四、应用界面与使用流程#

回到移动端本身。GazeKeep 客户端界面基于 Compose Multiplatform 结合 miuix 设计语言开发,追求克制、现代且符合系统设置层级的直觉体验:

主页运行状态与环境概览
主页状态与环境概览
检测与保护参数设置
检测与保护参数设置
三种工作后端与自动选择
三种工作后端与优选
应用白名单管理
应用白名单定向生效

4.1 下载与架构选择#

前往 GitHub Releases 下载最新发布的正式签名安装包。构建产物按 CPU 架构进行了分包,体积控制极为精简:

安装包架构适用设备说明包体特点
arm64-v8a(强烈推荐)绝大多数近几年的主流 64 位 Android 手机与平板针对 64 位指令集优化,单包体积仅约 10~11 MB
armeabi-v7a早期的老旧 32 位 Android 设备兼容老旧低配置架构,体积约 10 MB
x86_64PC Android 模拟器适用于开发调试或模拟器内体验
universal全架构集成通用包包含所有 ABI 原生库(约 17 MB),不确定架构时首选

4.2 首次启用四步走#

安装完毕后,按照以下四步即可完成配置并开始使用:

实现方式
  1. 授予权限:
    打开 GazeKeep,授予前置相机权限(仅在快熄屏前瞬时采样)。对于 Android 13+ 设备,建议同时授予通知权限,当后端掉线或后台发生异常时能够及时收到提醒。
  2. 两步相机自检:
    进入「相机自检」向导页面:
    • 第一步(正视屏幕):端坐并正常注视屏幕,检测成功后判定为「注视了屏幕」;
    • 第二步(移开视线):将头偏向一侧或看向别处,检测成功后判定为「未注视屏幕」。
      自检向导不仅能帮助用户直观理解判定的界限,也能验证当前设备的相机驱动与 ML 推理环境是否正常运转。
  3. 设置生效应用白名单:
    GazeKeep 默认开启白名单过滤,避免在全局所有应用甚至桌面上无差别唤醒相机。在「生效应用」中勾选你日常需要长时间专注阅读的 App(如微信读书、知乎、各类浏览器、代码查看器或菜谱软件)。
  4. 确认后端就绪并开启总开关:
    在首页确认至少有一个后端处于“已就绪”状态,滑动开启顶部的「注视保亮」主开关。
    此时,将系统的自动熄屏时间设为 15 秒或 30 秒,打开白名单中的阅读应用,即可享受目光注视下持续亮屏的惬意体验。

4.3 关键系统后台保活与避坑指南#

为了保证在熄屏倒计时阶段准时唤醒,GazeKeep 需要依赖底层常驻服务的调度。针对不同厂商 ROM 的后台电源管理策略,建议按需配置:

WARNING

特别注意:小米 / 澎湃 HyperOS 设备的后台冻结问题
实测在 Xiaomi / HyperOS 设备上(基于 HyperOS 2.0 实测),系统默认的“智能推荐”省电策略会在用户调用一次系统相机后,将后台的 GazeKeep 深度冻结,且在退出相机后不会主动解冻,此时即使勾选了忽略电池优化也无济于事。
解决方式:进入系统「应用设置」或 GazeKeep 内的「后台运行」指引,将 GazeKeep 的省电策略彻底改为**「无限制」**。修改该策略时系统会强制关闭一次 App,修改完成后重新打开一次 GazeKeep 即可保持常驻。

  • 华为 / 荣耀 / 魅族 / OPPO / vivo:进入多任务后台卡片界面,将 GazeKeep 卡片下拉加锁,并在系统设置中允许应用后台自启动与保持唤醒。

五、深入解析:三大工作后端的技术原理#

为了覆盖不同折腾程度与不同权限层级的设备,GazeKeep 抽象出了统一的保亮与前台感知接口,并实现了三种截然不同的工作后端:

后端方案权限与门槛保亮实现原理核心优势体验评分
LSPosed已 Root,安装 LSPosed 框架注入 system_server 的 PowerManagerService原生级事件注入,零模拟触控,支持过滤绿点★★★★★
Shizuku免 Root,需 ADB/无线调试授权通过特权服务向系统调度或重置息屏计时器无需解 BL 锁或 Root,原生级事件调度★★★★☆
无障碍服务零门槛,开箱即用借助辅助功能服务发送系统级无感触控脉冲所有人都能用,老旧平板即装即用★★★☆☆

5.1 LSPosed 框架后端(极客推荐:终极原生体验)#

对于已解锁 Bootloader、刷入 Magisk / KernelSU / APatch 并配置了 LSPosed 的深度玩家,LSPosed 后端提供了最完美的系统级整合:

  • 系统服务级注入:在 LSPosed 管理器中启用 GazeKeep 模块,推荐勾选作用域为「系统框架(android)」。当系统启动时,GazeKeep 钩子直接注入进 system_server 进程。当注视判定成功时,通过框架直接向 PowerManagerService 发送 userActivity 信号,性能开销趋近于零。
  • 相机隐私指示器单向过滤(实验性):新版 Android 在应用调用相机时会在状态栏强制弹出绿色小圆点。为了减少频繁采样带来的视觉干扰,LSPosed 后端提供了可选开关:仅在 system_server 内部单向过滤 GazeKeep 自身 UID 的 OP_CAMERA 活跃通知,绝不修改全局系统配置,关闭开关或切换后端后立即恢复。

5.2 Shizuku 后端(免 Root 用户的平衡之道)#

如果你不想解锁刷机,但希望获得比无障碍更稳定的后台调度,可以使用 Shizuku:

  • 通过 Android 11+ 自带的「无线调试」或电脑连接 USB 执行一次 ADB 命令启动 Shizuku 服务;
  • 在 GazeKeep 中授予 Shizuku 权限;
  • Shizuku 后端通过特权进程直接执行系统级命令或调用隐藏 API 重置息屏计时器,并能极其精准地通过 IActivityManager 判定当前顶层应用。

5.3 系统无障碍服务后端(零门槛,开箱即用)#

如果只是一台给长辈阅读、或者不想折腾任何调试命令的旧设备:

  • 在系统「设置 →\to 无障碍 / 辅助功能」中找到 GazeKeep 并开启服务即可;
  • 纯净与安全保证:查看项目源码中的无障碍配置文件:
apps/app/backend/a11y/src/main/res/xml/accessibility_service_config.xml
<?xml version="1.0" encoding="utf-8" ?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowStateChanged|typeTouchInteractionStart"
android:accessibilityFeedbackType="feedbackGeneric"
android:canRetrieveWindowContent="false"
android:description="@string/a11y_service_description"
android:notificationTimeout="100"
/>

注意第 6 行的声明:android:canRetrieveWindowContent="false"。这意味着从 Android 操作系统层面,GazeKeep 的无障碍服务根本没有权限读取当前屏幕上的任何文字、输入框或界面节点内容,它仅仅用于捕获窗口切换事件以更新当前白名单状态,并在临近熄屏时发送无感的交互保亮信号。

5.4 Auto 智能选择机制#

GazeKeep 默认采用 Auto(自动)模式,调度器会严格按照:

LSPosed 模块⟶Shizuku⟶无障碍服务\text{LSPosed 模块} \longrightarrow \text{Shizuku} \longrightarrow \text{无障碍服务}

的优先级顺序,自动探测并绑定当前设备上第一个就绪的后端。当然,用户也可以在设置中将后端手动锁定为某一特定方案。当手动锁定的后端发生授权过期或掉线时,系统会弹出通知提醒,绝不会静默切换到其他非预期后端。

六、核心源码解析:端侧离线检测与低功耗架构#

GazeKeep 是如何做到既能精准识别注视,又把功耗与相机占用压缩到几乎感知不到的程度?我们结合项目中的核心 Kotlin 源码来拆解其设计精妙之处。

6.1 暗光快速拦截:LumaProbe(毫秒级灰度探针)#

如果环境极其黑暗(如关灯后的卧室),启动复杂的人脸检测网络不仅大概率检测失败,还会徒增几十毫秒的 CPU 功耗。

GazeKeep 在设计上引入了 LumaProbe 亮度探针:在相机吐出首帧原始 YUV 图像后,不急于送入神经网络,而是优先通过纯算法计算图像 Y 平面(亮度分量)的平均照度:

apps/app/engine/src/main/kotlin/cn/rainafter/app/gazekeep/engine/classify/LumaProbe.kt
package cn.rainafter.app.gazekeep.engine.classify
import androidx.camera.core.ImageProxy
/** 只读取 Y 平面,先于模型拦截明显暗光帧 */
object LumaProbe {
const val DEFAULT_MIN_LUMA = 25.0
fun mean(image: ImageProxy, step: Int = 8): Double {
require(step > 0)
val plane = image.planes.firstOrNull() ?: return 0.0
val buffer = plane.buffer.duplicate()
val rowStride = plane.rowStride
val pixelStride = plane.pixelStride
var sum = 0L
var count = 0L
var y = 0
while (y < image.height) {
var x = 0
while (x < image.width) {
val index = y * rowStride + x * pixelStride
if (index < buffer.limit()) {
sum += buffer.get(index).toInt() and 0xff
count++
}
x += step // 步长采样,极大降低遍历开销
}
y += step
}
return if (count == 0L) 0.0 else sum.toDouble() / count
}
fun isTooDark(image: ImageProxy, minLuma: Double = DEFAULT_MIN_LUMA): Boolean =
mean(image) < minLuma
}

通过设置 step = 8 的步长进行降采样,算法仅耗费不到 1ms 即可计算出画面的平均亮度。一旦发现 isTooDark 成立(平均亮度小于 25.0),流程立即返回 FrameVerdict.NotLooking(Reason.TooDark) 并放行熄屏,直接掐断后续沉重的模型推理。

6.2 端侧注视判定策略:AttentionJudge#

在亮度达标后,图像才会被送入基于 Google ML Kit 的端侧检测器中,提取人脸的三维旋转姿态与眼部特征。随后,核心策略决策函数 judgeFeatures 会对特征进行严密的多重约束校验:

apps/app/core/src/commonMain/kotlin/cn/rainafter/app/gazekeep/core/policy/AttentionJudge.kt
package cn.rainafter.app.gazekeep.core.policy
import cn.rainafter.app.gazekeep.core.model.ClassifierThresholds
import cn.rainafter.app.gazekeep.core.model.FaceFeatures
import cn.rainafter.app.gazekeep.core.model.FrameVerdict
import cn.rainafter.app.gazekeep.core.model.Sensitivity
import kotlin.math.abs
fun judgeFeatures(
features: FaceFeatures,
sensitivity: Sensitivity,
thresholds: ClassifierThresholds = ClassifierThresholds(),
): FrameVerdict {
// 1. 无人脸或画面中有多张人脸(有路人入画):果断放行熄屏
if (features.faceCount <= 0) return FrameVerdict.NotLooking(FrameVerdict.Reason.NoFace)
if (features.faceCount > 1) return FrameVerdict.NotLooking(FrameVerdict.Reason.MultipleFaces)
// 2. 面部占比过小(距离过远,无法确信是当前使用者):放行熄屏
if (features.faceWidthRatio < thresholds.minFaceWidthRatio) {
return FrameVerdict.NotLooking(FrameVerdict.Reason.FaceTooSmall)
}
// 3. 头部转动(俯仰角 pitch 或偏航角 yaw 超出阈值,说明在看别处或侧脸):放行熄屏
if (abs(features.yawDeg) > thresholds.maxYawDeg || abs(features.pitchDeg) > thresholds.maxPitchDeg) {
return FrameVerdict.NotLooking(FrameVerdict.Reason.HeadTurned)
}
// 4. 宽松模式下直接认可;标准/严格模式下校验双眼睁眼概率(闭眼打盹直接放行)
if (sensitivity == Sensitivity.Loose) return FrameVerdict.Looking
if ((features.leftEyeOpenProbability ?: 0f) < thresholds.minEyeOpen ||
(features.rightEyeOpenProbability ?: 0f) < thresholds.minEyeOpen
) {
return FrameVerdict.NotLooking(FrameVerdict.Reason.EyesClosed)
}
// 所有条件严密吻合:判定为当前正在注视屏幕
return FrameVerdict.Looking
}

这段逻辑体现了 GazeKeep 的工程精细度:

  • faceCount > 1 拒绝保亮:如果旁边有室友或同事走过,不会因为背景中偶然出现的脸孔误导致屏幕常亮;
  • faceWidthRatio 距离门槛:防止放在几米开外充电的手机因为捕捉到远处的模糊人影而持续亮屏;
  • 姿态与睁眼校验:只有面部正面朝向屏幕,且左右眼均处于睁开状态时,才给出 Looking 判定。

6.3 严格的瞬时生命周期与内存释放#

相机硬件在 Android 属于极度敏感且消耗巨大的独占资源。在 CameraXFrameSource.kt 中,GazeKeep 对每一帧的内存释放做了严苛的保护:

apps/app/engine/src/main/kotlin/cn/rainafter/app/gazekeep/engine/camera/CameraXFrameSource.kt
/** 图像在同步回调返回后必须关闭,随后由调用方发布结果并解绑相机 */
internal fun analyzeFrame(image: ImageProxy, onFrame: (ImageProxy) -> Boolean): Result<Boolean> = try {
Result.success(onFrame(image))
} catch (error: Throwable) {
Result.failure(error)
} finally {
image.close() // 严格在 finally 块中释放硬件缓冲,绝不存盘,杜绝内存泄漏
}

而在 AttentionCaptureSession 会话层,每次采样引入了 AttentionVoter 机制:最多采样 3 帧,但只要前两帧已经稳定得出结论(例如连续判定为注视中,或者首帧就判定为无人脸/暗光),回调就会立刻返回 false,CameraX 会在数十毫秒内立即执行 provider.unbind(analysis) 解绑相机。这就是为什么在日常使用中,你几乎感受不到前置相机的存在。

七、极致克制的隐私与安全设计#

对于任何一款需要申请相机权限的软件,用户的信任都是第一位的。GazeKeep 将“安全与隐私”写进了项目的核心规范中。

7.1 三句核心隐私真源#

在 GazeKeep 官方文档与 UI 的隐私政策中,始终遵循三句固定真源:

  1. 只在快要熄屏时打开前置摄像头,看完立刻关闭。
  2. 画面只在内存里判断是否注视了屏幕,不保存、不上传。
  3. 看不清、没看清、旁边有别人,都会让屏幕正常熄灭。

7.2 物理级权限剥离#

很多工具类应用往往在权限声明中留后门,而 GazeKeep 从 Android 底层权限表上就彻底掐断了任何数据外泄的可能:

apps/app/android/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 仅申请前置相机与必要前台服务权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- 核心:显式移除网络权限,即便传递依赖引入也会在打包合并时强制剔除 -->
<uses-permission android:name="android.permission.INTERNET" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" tools:node="remove" />
<!-- 绝不申请 READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE -->
<!-- 绝不申请 QUERY_ALL_PACKAGES 或 SYSTEM_ALERT_WINDOW 悬浮窗权限 -->
...

注意上面的 tools:node="remove":GazeKeep 在清单文件中对 android.permission.INTERNET 做出了强制移除指令。这意味着即便引用的某些 AndroidX 依赖库暗中声明了网络权限,Gradle 在打包 APK 时也会将其强行剔除。在系统沙箱层面,GazeKeep 根本没有联网的能力,从物理上杜绝了任何数据被上传云端的可能。

此外:

  • 不申请存储读写权限:没有本地文件读写权限,前置相机采样帧只存在于内存中的 ImageProxy,使用完毕即刻 close(),不写任何临时文件或缓存盘;
  • 零商业 SDK:整个项目干干净净,没有集成任何广告 SDK、统计埋点 SDK、或第三方崩溃收集组件;
  • 唯一的临时预览:相机画面预览仅出现在用户主动发起的「相机自检」向导页面中,退出自检向导即刻销毁预览 Surface。

八、关键参数调优建议#

进入 GazeKeep 的「设置」页面,可以根据手头设备的硬件条件与个人使用习惯微调检测参数:

GazeKeep 调优参数总览:
├── 采样提前量(默认:3 ~ 5 秒)
├── 判定灵敏度(标准 / 严格 / 宽松)
├── 单次保亮上限(默认:30 分钟)
├── 应用白名单机制(默认:开启)
└── 本地调试日志(默认:关闭,自动轮转)
  • 采样提前量:决定系统在息屏前几秒启动相机检测。对于处理器性能较老、相机冷启动较慢的旧设备,或者系统降亮(Dim)过程极其短暂的机型,建议将提前量调至 4~5 秒;如果设备启闭相机非常迅速,使用默认 3 秒即可。
  • 判定灵敏度:
    • 标准模式(默认):综合校验面部比例、转头姿态与睁眼概率,兼顾准确率与防误判;
    • 严格模式:进一步收紧面部转角与睁眼阈值,适合对防止误常亮有极高要求的场景;
    • 宽松模式:仅校验人脸朝向,不严格限制睁眼概率,适合习惯佩戴反光眼镜或低头角度较大的用户。
  • 单次保亮上限:建议保持 30 分钟默认值。给设备加上一道兜底锁,避免在极端情况下产生无意义的电量消耗。

九、结语#

很多时候,新设备的发布会总在强调更大底的传感器、更极限的算力跑分与更奢华的机身材质。但回到日常使用中,那台屏幕泛黄但依然通透的旧阅读器、那台被擦拭干净立在书桌一角的备用机,依然能在安静的角落里发挥作用。

硬件其实并未过时,它们只是缺少了一段恰到好处的软件逻辑。

GazeKeep 是一次用纯粹的开源工程为旧设备注入新体验的尝试。从 Android 底层的微秒采样与跨后端调度,到官网上一抹呼吸流转的 Shader 微光,目标始终如一:目光所及,屏幕常明;目光离开,屏幕安然休眠。

相关资源与链接#

如果这款工具改善了你手头设备的使用体验,欢迎前往 GitHub 为项目点一个 Star 🌟,或者提交 Issue / PR 交流探讨!

为你的 Android 设备补齐注视不熄屏功能 —— GazeKeep 使用指南与原理解析
https://www.rainafter.cn/posts/为你的-android-设备补齐注视保亮功能--gazekeep-使用指南/
作者
宇文Teacher
发布于
2026-10-29
许可协议
CC BY-NC-SA 4.0