Android全局监听音量按键事件

Hi,I'm Shendi

最近在编写Android自动化之类的东西,对于触发器我选用了音量键,在这里记录一下


Android全局监听音量按键事件


Android全局监听音量按键事件

有多种方式,但效果和兼容性都不太理想,最终我选择了无障碍+音量广播二合一的方式

无障碍监听按键事件

用户体验

  • 需要手动打开无障碍
  • 在某些手机上有熔断问题(小米实测,按几下后就监听不到了,得重启手机才能继续监听)

实现

在 res/xml 中新建无障碍配置文件 accessibility_service_config.xml,如下

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="50"
    android:canRetrieveWindowContent="true"
    android:accessibilityFlags="flagDefault"
    android:canRequestFilterKeyEvents="true"
    android:canRequestTouchExplorationMode="true"
    android:accessibilityFeedbackType="feedbackAllMask"
/>

上方的 android:canRequestFilterKeyEvents="true" 是必须的,允许无障碍服务接收并过滤按键事件(包括音量键)

新建无障碍服务类,如下

java 复制代码
public class VolumeKeyAccessibilityService extends AccessibilityService {

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();

        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
        info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
        // 监听按键事件的flags,必须要代码加才能监听到
        info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS;
        info.notificationTimeout = 50;

        setServiceInfo(info);
    }

    @Override
    public boolean onKeyEvent(KeyEvent event) {

        int keyCode = event.getKeyCode();

        if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                Log.i("VolumeKey", "音量 + 按下");
            } else if (event.getAction() == KeyEvent.ACTION_UP) {
                Log.i("VolumeKey", "音量 + 抬起");
            }
            return true; // 拦截按键(不让系统调音量)
        }

        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                Log.i("VolumeKey", "音量 - 按下");
            } else if (event.getAction() == KeyEvent.ACTION_UP) {
                Log.i("VolumeKey", "音量 - 抬起");
            }
            return true;
        }

        // 返回 false 表示按键传递给系统
        return false;
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // 不需要处理无障碍事件
    }

    @Override
    public void onInterrupt() {

    }
}

清单文件中配置服务

xml 复制代码
<service
    android:name=".VolumeKeyAccessibilityService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
    android:exported="false">

    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>

    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
</service>

广播监听音量变化

我将其作为无障碍无法正确监听的备用选项。

监听的是音量变化,所以当音量为0,按下音量下键不会触发,音量100按下音量上键不会触发。

实现

注册广播接收器

java 复制代码
// 注册广播接收器
IntentFilter filter = new IntentFilter();
// 音量修改事件
filter.addAction("android.media.VOLUME_CHANGED_ACTION");

registerReceiver(receiver, filter);

广播接收器

java 复制代码
/** 最后一次手机的音量 */
private int lastVolume = -1;

private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        switch (intent.getAction()) {
            // 音量变动
            case "android.media.VOLUME_CHANGED_ACTION": {
                int newVolume = intent.getIntExtra("android.media.EXTRA_VOLUME_STREAM_VALUE", -1);

                if (lastVolume == -1) {
                    lastVolume = newVolume;
                    return;
                }

                if (newVolume > lastVolume) {
                    // 等价于音量上键
                    onVolumeUp();
                } else if (newVolume < lastVolume) {
                    // 等价于音量下键
                    onVolumeDown();
                }

                lastVolume = newVolume;
                break;
            }
        }
    }
};
                

END

相关推荐
七夜zippoe1 小时前
基于MLC-LLM的轻量级大模型手机端部署实战
android·智能手机·架构·大模型·mlc-llm
darryrzhong2 小时前
GalleryPicker:一个基于 Android 官方 Photo Picker API 封装的现代图片/视频选择库
android·kotlin·github·相机
wangchen_02 小时前
MySQL在C/C++中的使用
android
天青Giser11 小时前
Android开发记录
android
子春一11 小时前
Flutter 与原生平台深度集成:打通 iOS 与 Android 的最后一公里
android·flutter·ios
小邓   ༽12 小时前
全场景Android测试:API、工具与案例,从TestCase到Mock类应用指南
android·android 测试·android 组件测试·mock 类·测试 api 应用·组件测试核心
享哥。15 小时前
android MVP模式代码示例
android
qq_7174100116 小时前
删除设置-流量使用情况、更多
android