Implement KeyEvent.Callback by Mapping Air Actions

Objective

Learn how to implement KeyEvent.Callback on your S Pen Remote by mapping the Air Actions to a car racing game.

Overview

S Pen connects via Bluetooth Low Energy (BLE) to a device and the S Pen Framework manages the connection.

BLE events are converted by the S Pen Framework into KeyEvents before sending to the app.

Apps are able to handle S Pen events by reusing existing KeyEvent.Callback without adding other interfaces.

Collecting and Sending S Pen Remote Events to Apps

The S Pen Framework collects and manages KeyEvents to be received by the app, and are defined in .xml format before making them public.

Below is the process of the S Pen Remote Event handling and sending S Pen Remote Event-defined KeyEvents to apps:

  1. BLE event is sent to the S Pen Framework.
  2. The S Pen Framework checks for the foreground app and looks for the KeyEvent that the app made public.
  3. The found KeyEvent is sent to the app's KeyEvent.Callback.
  4. The app performs the actions defined in the KeyEvent.

Set up your environment

You will need the following:

  • Java SE Development Kit 10 (JDK) or later
  • Android Studio (latest version recommended)
  • Samsung Galaxy device with S Pen Remote capability:
    • Galaxy Note10 series or newer
    • Galaxy Tab S6 series or newer
    • Galaxy S22 Ultra

Sample Code

Here is a sample code for you to start coding in this Code Lab. Download it and start your learning experience!

Air Actions Sample Code
(6.62 MB)

Start your project

In Android Studio, click Open an existing Android Studio project.

Locate the Android project from the directory and click OK.

Implement Remote Actions

  1. Check for the activity to handle the KeyEvent in a manifest file, AndroidManifest.xml.

  2. Add <intent-filter> and <meta-data> elements to that activity. AndroidManifest.xml resource file defining RemoteActions must be specified for <meta-data>.

    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.example.spenremote.racingcar">
    
        <application ...
            <activity android:name=".MainActivity"
                <intent-filter>
                    <action android:name="com.samsung.android.support.REMOTE_ACTION" />
                </intent-filter>
                <meta-data
                    android:name="com.samsung.android.support.REMOTE_ACTION"
                    android:resource="@xml/remote_action_sample"/>
            </activity>
        </application>
    
    </manifest>
    
    
  3. Create an .xml file under res/xml/.
    (Name the file with the same name as the resource specified previously)

  4. Create the desired <action> elements in the XML file created as seen below. XML has a root element of <remote-actions>, and may include several <action> elements. In addition, each <action> contains information about id, label, priority, trigger_key, etc. If you want to map a default action to a specific gesture, you need to add a <preference> element:

    
    <?xml version="1.0" encoding="utf-8"?>
    <remote-actions version="1.2">
        <action
            id="pause_or_resume"
            label="@string/pause_or_resume"
            priority="1"
            trigger_key="SPACE">
            <preference name="gesture" value="click"/>
            <preference name="button_only" value="true"/>
        </action>
        <action
            id="move_left"
            label="@string/move_car_left"
            priority="2"
            trigger_key="DPAD_LEFT">
            <preference name="gesture" value="swipe_left"/>
            <preference name="motion_only" value="true"/>
        </action>
        <action
            id="move_right"
            label="@string/move_car_right"
            priority="3"
            trigger_key="DPAD_RIGHT">
            <preference name="gesture" value="swipe_right"/>
            <preference name="motion_only" value="true"/>
        </action>
        <action
            id="restart"
            label="@string/restart"
            priority="4"
            trigger_key="CTRL+R">
            <preference name="gesture" value="circle_cw|circle_ccw"/>
            <preference name="motion_only" value="true"/>
        </action>
    </remote-actions>
    
    

Implement KeyEvent.Callback

Apply the KeyEvent.Callback to the activity where RemoteActions have been declared. It is recommended to handle the sent KeyEvent at onKeyDown.

Add the following KeyEvent.Callback as seen below:

  1. Space key: Pause or Resume the racing game
  2. Left key: Move the car to left direction
  3. Right key: Move the car to right direction
  4. Ctrl + R key: Restart the racing game

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_SPACE) {
        RacingCar.PlayState state = racingCar.getPlayState();
        if (state == RacingCar.PlayState.Playing) {
            pause();
        } else {
            resume();
        }
    } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
        moveCarTo(RacingCar.POS_LEFT);
    } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
        moveCarTo(RacingCar.POS_RIGHT);
    } else if ((event.getMetaState() & KeyEvent.META_CTRL_ON) != 0
            && (keyCode == KeyEvent.KEYCODE_R)) {
        restart();
    }

    return super.onKeyDown(keyCode, event);
}


Run the app

Now, everything is ready. When you install your app, make sure that your app icon appears properly in the settings,
Settings > Advanced features > S Pen > Air actions.

You can now control the car in the game using Air actions.

You're done!

Congratulations! You have successfully achieved the goal of this Code Lab. Now, you can map air actions events on a game or app by yourself! If you're having trouble, you may download this file:

Air Actions Complete Code
(6.63 MB)