简单记录qti haptics effect优化
侧边栏壁纸
  • 累计撰写 7 篇文章
  • 累计收到 2 条评论

简单记录qti haptics effect优化

ReallySnow
2023-11-03 / 0 评论 / 85 阅读 / 正在检测是否收录...

正常情况下,无论是 Awinic Haptics 还是 QTI Haptics 其实 HAL 实现代码都大同小异,甚至后者的代码可以给前者使用,但是在部分情况下,会表现出缺少震动效果的问题,例如部分类原生 ROM 的亮度条震动和所有类原生 ROM 的后台卡片震动,因为这部分使用的震动效果是 TICK,而 HAL 无法正确响应 TICK 操作将数值写入到没核节点中,从而导致震动失效。
对此,我们需要通过修改 HAL 的源码来实现这些操作,以下操作将以联想拯救者Y70进行操作

前提条件

  1. 手机需要 Root
  2. ADB
  3. 确保官方 ROM 有 strace 命令(没有也没关系,你都有 root 了我想你也知道怎么做)
  4. VibeTest

读取官方 ROM 相关效果写入内核的值

首先 ADB 连接手机并授予adb shell权限
确定 vibrator 服务相关的 PID,例如现在 拯救者 Y70 手机的震动服务为 114514
然后我们使用 strace 来跟踪 vibrator 服务的一些操作

strace -fp 114515 -e openat,write

然后打开 VibeTest 软件,依次点击以下特效并记录 strace 输出的日志

CLICK,DOUBLE_CLICK,TICK,THUD,POP,HEAVY_CLICK

分析日志

这里我们使用CLICK效果来说明
日志输出为下文

openat(AT_FDCWD, "/sys/class/leds/vibrator/state", O_WRONLY) = 8
write(8, "1\0", 2)                      = 2
openat(AT_FDCWD, "/sys/class/leds/vibrator/duration", O_WRONLY) = 8
write(8, "60\n\0", 4)                   = 4
openat(AT_FDCWD, "/sys/class/leds/vibrator/activate", O_WRONLY) = 8
write(8, "1\0", 2)                      = 2
strace: Process 10208 attached
[pid  1196] openat(AT_FDCWD, "/sys/class/leds/vibrator/activate", O_WRONLY) = 8
[pid 10208] +++ exited with 0 +++
write(8, "0\0", 2)                      = 2

说明官方震动 HAL 对以下内核节点写入了下列值

内核节点
/sys/class/leds/vibrator/state1
/sys/class/leds/vibrator/duration60
/sys/class/leds/vibrator/activate1

修改 HAL 代码

Vibrator.cpp

创建map来记录相关内核节点和值,代码如下(这里用CLICK举例)

static std::map<Effect, std::vector<std::pair<std::string, std::string>>> LED_EFFECTS{
    { Effect::CLICK, {
        { "/sys/class/leds/vibrator/state", "1" },
        { "/sys/class/leds/vibrator/duration", "60" },
        { "/sys/class/leds/vibrator/activate", "1" },
    }}
};

修改ndk::ScopedAStatus Vibrator::perform方法
修改下列代码

if (ledVib.mDetected)
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
 (effect < Effect::CLICK ||
        effect > Effect::HEAVY_CLICK)
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && es != EffectStrength::STRONG)
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
ret = ff.playEffect((static_cast<int>(effect)), es, &playLengthMs);
if (ret != 0)
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));

if (ledVib.mDetected) {
    if (const auto it = LED_EFFECTS.find(effect); it != LED_EFFECTS.end()) {
        for (const auto &[path, value] : it->second) {
            if (path == "SLEEP") {
                usleep(atoi(value.c_str()) * 1000);
            } else {
                ledVib.write_value(path.c_str(), value.c_str());
            }
        }
        playLengthMs = 150;
    } else {
        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
    }
} else {
    if (effect < Effect::CLICK ||
            effect > Effect::HEAVY_CLICK)
        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));

    if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && es != EffectStrength::STRONG)
        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));

    ret = ff.playEffect((static_cast<int>(effect)), es, &playLengthMs);
    if (ret != 0)
        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
}

修改ndk::ScopedAStatus Vibrator::getSupportedEffects方法

将下列代码

if (ledVib.mDetected)
        return ndk::ScopedAStatus::ok();

修改为

if (ledVib.mDetected)
    *_aidl_return = {Effect::你要支持的效果};

Vibrator.h

公开write_value方法
int write_value(const char *file, const char *value);上的private:拿掉即可

0

评论 (0)

取消