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:
- BLE event is sent to the S Pen Framework.
- The S Pen Framework checks for the foreground app and looks for the KeyEvent that the app made public.
- The found KeyEvent is sent to the app's KeyEvent.Callback.
- 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 Tab S6 series or newer
- Galaxy S22 Ultra or newer
- Galaxy Fold3 or newer
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.4 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
-
Check for the activity to handle the KeyEvent in a manifest file, AndroidManifest.xml
.
-
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>
NoteOnly one RemoteAction
per app is allowed at the moment. If you define RemoteActions
to several activities, all other except one may be ignored.
-
Create an .xml
file under res/xml/.
(Name the file with the same name as the resource specified previously)
-
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:
- Space key: Pause or Resume the racing game
- Left key: Move the car to left direction
- Right key: Move the car to right direction
- 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);
}
NotePay attention to cases when the child view consumes the KeyEvent
. For example, if the EditText
is focused on a screen where the EditText
co-exists, most KeyEvents
will be consumed for text inputs or a cursor movement and they may not be sent to the Activities or Container Layouts. On this screen, you must specify the key code or key combination that the child view cannot consume.
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.4 MB)