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

相关推荐
andr_gale10 小时前
04_rc文件语法规则
android·framework·aosp
祖国的好青年11 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴11 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭12 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首12 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
zhangphil13 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙13 小时前
echarts,3d堆叠图
android·3d·echarts
李白的天不白13 小时前
如何项目发布到github上
android·vue.js
summerkissyou198713 小时前
Android-RTC、NTP 和 System Time(系统时间)
android