Android background service monitoring key (home,back, volume key)

Keywords: Android xml Database encoding

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" />

Posted by iimrii on Fri, 03 Apr 2020 13:11:54 -0700