0

I have read here how can I listen to hardware when Activity is in Running state:

@Override
public boolean onKeyDown(int keycode, KeyEvent e) {
    switch(keycode) {
        case KeyEvent.KEYCODE_MENU:
            doSomething();
            return true;
    }

    return super.onKeyDown(keycode, e);
}

I want to use "trigger" button to open/bring forward my app (my MainActivity), if it is in the background (activity stopped) or not running at all (not launched yet or shut down).

Questions:

  1. Can I listen to the hardware keyboard from Android Service and open/bring forward Activity?

  2. How can I do that?

My application is a Barcode/RFID tool that will run on devices like this:

enter image description here

Industrial environment where it will work needs something like "run app immediately and scan" functionality, no matter what is on the screen. Ideally it would be awseome if it could wake up whole device to make warehouse work easier.

This is why I need this.

Kamil
  • 13,363
  • 24
  • 88
  • 183
  • "Can I listen to the hardware keyboard from Android Service and open/bring forward Activity?" -- you cannot open an activity from the background on modern versions of Android. Also, most hardware key events do not result in anything that a service listen for. – CommonsWare Sep 22 '22 at 13:34
  • @CommonsWare I have found promising solution that uses AccessibilityService. I have to try it. Link: https://stackoverflow.com/a/60953997/1215291 – Kamil Sep 22 '22 at 15:15

1 Answers1

0

So at this moment (september 2022) Android Development Guide says, that there are restrictions on starting activities from the background. There are some exceptions.

In my case (inventory management app with dedicated barcode/RFID reader hardware) I should make use of exception for dedicated devices or use some Device Policy Controller:

The app is a device policy controller running in device owner mode. Example use cases include fully managed enterprise devices, as well as dedicated devices like digital signage and kiosks.

https://developer.android.com/work/dpc/dedicated-devices

However, for development purposes I have tried the AccessibilityService, as suggested here: link

I have added startActivity when the key 293 is pressed (trigger key on device). In comparison to answer linked above - I have choosen diffrent name for service class. Rename has to be done also in XML file.

src/AccessibilityKeyDetectorService.java

public class AccessibilityKeyDetectorService extends AccessibilityService {

    private final String TAG = "AccessKeyDetector";

    @Override
    public boolean onKeyEvent(KeyEvent event) {
        Log.d(TAG,"Key pressed via accessibility is: "+event.getKeyCode());

        if (event.getKeyCode() == 293)
        {
            Intent intent = new Intent(this,  MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // this is required to open Activity from service
            startActivity(intent);

        }
        return super.onKeyEvent(event);
    }


    @Override
    protected void onServiceConnected() {
        Log.i(TAG,"Service connected");

    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {

    }


    @Override
    public void onInterrupt() {

    }
}

My res/xml/accessibility_service.xml:

<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityFlags="flagRequestFilterKeyEvents"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackAllMask"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:settingsActivity=""
    android:packageNames="pl.globalsystem.rflow"
    android:canRequestFilterKeyEvents="true" />

And my manifest entry:

<service android:name=".services.AccessibilityKeyDetectorService"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
            android:exported="true">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service" />
        </service>

And my MainActivity method for accessibility permissions:

public boolean checkAccessibilityPermission() {
        int accessEnabled=0;
        try {
            accessEnabled = Settings.Secure.getInt(this.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
        if (accessEnabled==0) {
            /** if not construct intent to request permission */
            Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            /** request permission via start activity for result */
            startActivity(intent);
            return false;
        } else {
            return true;
        }
    }
Kamil
  • 13,363
  • 24
  • 88
  • 183