保持屏幕常亮

视频通话时,用户通常手持或静置手机,开启扬声器,面对屏幕。这个过程中,会有长时间不触摸屏幕的情况,此时需要在视频过程中保持手机一直亮屏。具体方法可参考如何保持屏幕常亮

手机贴近、远离人耳时的亮屏、息屏

有时在嘈杂的环境中,用户会关闭扬声器,将手机贴近耳朵收听视频通话的声音,此时屏幕应该熄灭;手机离开耳朵时,再让屏幕重新亮起。

针对这一场景,系统提供了接近光锁,用于感知传感器与障碍物的距离远近,自动发起亮灭屏流程。下面的代码中,runningLock.RunningLockType.PROXIMITY\_SCREEN\_CONTROL 表示类型为接近光锁,锁的名称为 running\_lock\_text;lock.hold(-1) 表示永久持有接近光锁,参数也可以根据实际需要改为其它数字,表示持锁时长。

runningLock.create('running_lock_test', runningLock.RunningLockType.PROXIMITY_SCREEN_CONTROL, (err: Error, lock: runningLock.RunningLock) => {
  if (typeof err === 'undefined') {
    console.log('create running lock: ' + lock);
    this.recordLock = lock;
    try {
      lock.hold(-1);
      console.log('hold running lock success');
    } catch(err) {
      console.log('hold running lock failed, err: ' + err);
    }
  } else {
    console.log('create running lock failed, err: ' + err);
  }
});

手部误触传感器的判断

上面实现了手机贴耳息屏、离耳亮屏的需求,但是这里有一个缺陷,上面的方法只是感知了障碍物和传感器的距离发起亮、灭屏,这就意味着,我们用手或者其他部位遮挡了传感器,同样会触发灭屏。

而在视频通话过程中,用户经常会不小心用手挡住或者划过传感器,造成屏幕突然的一熄一亮,体验很差,容易对用户造成惊吓。因此,我们需要区分意外遮挡传感器和主动贴近耳朵遮挡传感器的场景。

手机贴耳场景和手部误触传感器的场景区别主要在于手机的运动状态,所以可以通过加速度传感器来判断手机状态以区分这两个场景。

sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {
  console.info("Succeeded in obtaining data. x: " + data.x + " y: " + data.y + " z: " + data.z);
}, { interval: 100000000 });

上面的代码中订阅了加速度传感器数据,分别打印了手机在静置、手持、贴耳三种场景的加速度传感器数据,如下图所示。

我们现在的需求是区分手机贴耳场景,观察以上数据可发现,手机贴耳时,z 的值和其他场景有很大不同,所以可以用 z 值来判断手机是否贴耳。修改代码逻辑后,只在手机贴耳时,订阅接近光锁,离耳时释放接近光锁。

这里的手机贴耳数据判断不够严谨,只是临时方案,可能在特殊场景下会判断错误。传感器子系统正在将这一需求整合进系统能力,未来实现之后不再需要开发者根据加速度判断手机是否贴耳,直接调用系统接口即可。

checkProximityOfEar(data: sensor.AccelerometerResponse): boolean {
  if (data.z < 5) {
    return true
  }
  return false
}

最终方案

总结最终实现视频通话过程中的亮屏、灭屏控制方案如下:

  1. 视频通话开始时,调用 window.setWindowKeepScreenOn 保持手机屏幕常亮;
  2. 订阅加速度传感器,根据加速度传感器返回的数据,判断手机是否贴耳。
  3. 手机贴耳时,申请持有接近光锁,自动发起灭屏、亮屏流程;手机离耳时,释放接近光锁,这样可避免误触传感器导致的意外灭屏。

注意

上面第3步中,一定要在手机重新亮起时释放接近光锁,否则会出现灭屏后手机离耳无法亮屏的情况。判断手机是否亮屏,可以通过电源的 power.isActive() 方法获取屏幕状态。

setAccelerometerSensor(isOn: boolean = true) {
  if (!isOn) {
    sensor.off(sensor.SensorId.ACCELEROMETER)
    return
  }

  sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {
    console.info("Succeeded in obtaining data. x: " + data.x + " y: " + data.y + " z: " + data.z);
    if (this.checkProximityOfEar(data)) {
      // 持有接近光锁
      this.setRunningLock()
    } else {
      // 一定要在屏幕亮起时取消接近光,否则无法重新亮屏
      if (power.isActive()) {
        setTimeout(() => {
          // 释放接近光锁
          this.setRunningLock(false)
        }, 500)
      }
    }
  }, { interval: 100000000 });
}

HarmonyOS码上奇行
9.2k 声望3.3k 粉丝

欢迎关注 HarmonyOS 开发者社区:[链接]