Hi,I'm Shendi
最近在编写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