0. Start the 1x1 size service window to monitor the change, and press the volume button
Touch screen events are not accepted.
public static final int FLAG_NOT_TOUCHABLE = 0x00000010;
When the window can get the focus (without setting the flag not focus option), the point device events (mouse, touch screen) outside the window range are still sent to the later window for processing. Otherwise, it will monopolize all point device events, regardless of whether they occur in the window scope or not.
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:
// Handle their own logic 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 window display
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);
}
}
Operation result
03-23 17:00:23.910: D/suhuazhi(8340): KEYCODE_VOLUME_UP
03-23 17:00:23.935: D/suhuazhi(8340): keyCode 24
1. Use ContentProvide to monitor database changes to monitor volume key changes
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;
}
}
}
}
Operation result
The disadvantage is that setting the past requires waiting about 1.5 seconds before triggering
03-23 15:03:17.490: D / lavadisplayhelp (2903): setmediavolume = 14 (triggered after 1.5 seconds) 03-23 15:03:18.005: D/LavaDisplayHelp(2903): onChange currMediaVolume = 14
2. Use broadcast to monitor the change of volume key
Yes, not bad. It's still as slow
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. Use accessibility to monitor volume key changes
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" />