Android 后台服务监听按键(home,back,音量键)
程序员文章站
2022-05-12 10:35:20
...
0.启动1x1大小服务窗口进行监听变化,音量按键下按
不接受触摸屏事件。
public static final int FLAG_NOT_TOUCHABLE = 0x00000010;
当窗口可以获得焦点(没有设置FLAG_NOT_FOCUSALBE选项)时,仍然将窗口范围之外的点设备事件(鼠标、触摸屏)发送给后面的窗口处理。否则它将独占所有的点设备事件,而不管它们是不是发生在窗口范围之内。
public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;
public class MonitorView extends View {
public MonitorView(Context context) {
super(context);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.d("suhuazhi", "keyCode " + event.getKeyCode());
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
// 处理自己的逻辑break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
Log.d("suhuazhi", "KEYCODE_VOLUME_DOWN");
if (mAudioUtil != null && isMediaVolumePowerSaveSettings) {
int currAudioVolume = mAudioUtil.getMediaVolume();
Log.d(TAG, "currMediaVolume = " + currAudioVolume);
if (AUDIO_ADJ == currAudioVolume) {
Log.d(TAG, "Down volume key resume");
mAudioUtil.setMediaVolume(AUDIO_ADJ);
isMediaVolumePowerSaveSettings = false;
}
}
break;
case KeyEvent.KEYCODE_VOLUME_UP:
Log.d("suhuazhi", "KEYCODE_VOLUME_UP");
break;
default:
break;
}
return super.dispatchKeyEvent(event);
}
}
Window 窗口显示
private void showWindow() {
if (mWindowManager == null) {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mMonitorView = new MonitorView(mContext);
}
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
1, 1, //Must be at least 1x1
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
//Don't know if this is a safe default
PixelFormat.TRANSLUCENT);
//Don't set the preview visibility to GONE or INVISIBLE
mWindowManager.addView(mMonitorView, params);
}
private void hideWindow() {
if(null != mWindowManager) {
mWindowManager.removeView(mMonitorView);
}
}
运行结果
03-23 17:00:23.910: D/suhuazhi(8340): KEYCODE_VOLUME_UP
03-23 17:00:23.935: D/suhuazhi(8340): keyCode 24
1.使用ContentProvide 监听数据库变化,来监听音量键变化
private void registerVolumeChangeReceiver() {
mSettingsContentObserver = new SettingsContentObserver(mContext, null);
mContext.getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver);
}
private void unregisterVolumeChangeReceiver(){
mContext.getContentResolver().unregisterContentObserver(mSettingsContentObserver);
}
public class SettingsContentObserver extends ContentObserver {
private int oldMediaVolume;
public SettingsContentObserver(Context c, Handler handler) {
super(handler);
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (mAudioUtil != null && isMediaVolumePowerSaveSettings) {
int currAudioVolume = mAudioUtil.getMediaVolume();
if (oldMediaVolume == currAudioVolume) {
return;
}
oldMediaVolume = currAudioVolume;
Log.d(TAG, "onChange currMediaVolume = " + currAudioVolume);
if (currAudioVolume == mAudioUtil.getMaxMediaVolume()) {
return;
}
if (AUDIO_ADJ - currAudioVolume > 0) {
Log.d(TAG, "Down volume key resume");
mAudioUtil.setMediaVolume(AUDIO_ADJ);
isMediaVolumePowerSaveSettings = false;
}
}
}
}
运行结果
缺点是设置过去需要等待约1.5秒才触发
03-23 15:03:17.490: D/LavaDisplayHelp(2903): setMediaVolume = 14 (1.5秒后才触发)
03-23 15:03:18.005: D/LavaDisplayHelp(2903): onChange currMediaVolume = 14
2.使用广播进行监听,来监听音量键变化
是的,没差,速度还是一样慢
private class VolumeReceiver extends BroadcastReceiver {
private int oldMediaVolume;
public void init(Context mContext) {
IntentFilter filter = new IntentFilter();
filter.addAction("android.media.VOLUME_CHANGED_ACTION");
mContext.registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")) {
if (mAudioUtil != null && isMediaVolumePowerSaveSettings) {
int currAudioVolume = mAudioUtil.getMediaVolume();
if (oldMediaVolume == currAudioVolume) {
return;
}
oldMediaVolume = currAudioVolume;
Log.d(TAG, "currMediaVolume = " + currAudioVolume);
if (currAudioVolume == mAudioUtil.getMaxMediaVolume()) {
return;
}
if (AUDIO_ADJ - currAudioVolume > 0) {
Log.d(TAG, "Down volume key resume");
mAudioUtil.setMediaVolume(AUDIO_ADJ);
isMediaVolumePowerSaveSettings = false;
}
}
}
}
}
3.使用无障碍,来监听音量键变化
public class PowerSaveMonitorService extends AccessibilityService {
private static final String TAG = PowerSaveMonitorService.class.getSimpleName();
@Override
protected boolean onKeyEvent(KeyEvent event) {
Log.i(TAG, "onKeyEvent");
int key = event.getKeyCode();
switch(key){
case KeyEvent.KEYCODE_VOLUME_DOWN:
Log.i(TAG, "KEYCODE_VOLUME_DOWN");
break;
case KeyEvent.KEYCODE_VOLUME_UP:
Log.i(TAG, "KEYCODE_VOLUME_UP");
break;
}
return super.onKeyEvent(event);
}
@Override
public void onInterrupt() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
String pkgName = event.getPackageName().toString();
String className = event.getClassName().toString();
int eventType = event.getEventType();
switch (eventType) {
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
break;
}
}
}
AndroidManifest.xml
<service
android:name=".service.PowerSaveMonitorService"
android:enabled="true"
android:exported="true"
android:label="@string/app_name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="@xml/accessibility_config"></meta-data>
</service>
accessibility_config.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:canRetrieveWindowContent="true"
android:description="@string/app_name"
android:notificationTimeout="100" />