Search code examples
androidkeyboard-shortcutsaccessibilityservice

Android: how to re-enable an accessibility service after each reboot?


The device we’re speaking about is an Android 8 head unit with an external USB keyboard attached. Well, I need to assign some tasks to this keyboard’s function keys, e.g. launching certain applications. Say, F4 can launch the media player, F5 the navigation app and so on. Either the Automate or the AutoInput Tasker plugin would be nice for this purpose, but all of this kind of applications use accessibility service for interacting with physical HID devices.

The big problem here is that this particular Android device regularly kills the accessibility services on (warm) reboot. Tried absolutely everything, from disabling power save mode to mark the Automate etc. as device admin app, nothing helped. So I have resigned and now I’m thinking for an alternative way to re-enable the appropriate accessibility service after the system disabled it after reboot for an unknown reason.

If the device was rooted I suppose there would be an easy way to restart an accessibility service by a shell command or whatever (just guessing, I’m pretty beginner in Android). But obviously I want to avoid rooting if possible. The ideal scenario would be to (auto)start a shell command / application / foreground service / whatever on each reboot – which would have enough administrative privileges to re-enable the accessibility service the system just have disabled during the reboot. Of course, all this stuffs without rooting the device. But I’m not really sure this can be done on Android (on Windows it would be enough a service running in System account, but Android is a different story).

A fair solution might be to

  1. root the device,
  2. install the shell command (application, foreground service, whatever) meant to restart the accessibility service after each reboot and
  3. unroot the device (using SuperSU by example) in order to protect the user and not to void the warranty.

Would anybody tell me whether the above solution can give the desired result, and – if so – may I have some guidelines how to do this?


Solution

  • to achieve your purpose you should work with BroadcastReceiver and jobIntentService

    first create a boot receiver

    public class BootReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
                MyService.enqueueWork(context, new Intent());
            }
        }
    
    }
    

    add it to the manifest

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    
    <receiver android:name=".BootReceiver">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
    </receiver>
    
    <service android:name=".MyService"
             android:permission="android.permission.BIND_JOB_SERVICE"/>
    

    Now you have to define your jobIntent

    public class MyService extends JobIntentService {
    
        public static final int JOB_ID = 0x01;
    
        public static void enqueueWork(Context context, Intent work) {
            enqueueWork(context, MyService.class, JOB_ID, work);
        }
    
        @Override
        protected void onHandleWork(@NonNull Intent intent) {
            // your code
        }
    
    }
    

    And that’s it. This will directly start the service (when running on pre-O platforms) or enqueue work for it as a job (when running on O and later). No matter what the platform is, everything you pass in enqueueWork will ultimately appears in onHandleWork.

    here is some useful links : link - link