Uinput: Add sync command to get a response when the command is processed
Bug: 291881033 Bug: 294275314 Test: manual Change-Id: Ie522ff44aa1cb7ceb7f21a23d6dd68efd1845f7c Merged-In: Ie522ff44aa1cb7ceb7f21a23d6dd68efd1845f7c
This commit is contained in:
@@ -153,6 +153,38 @@ Example:
|
||||
}
|
||||
```
|
||||
|
||||
4. `sync`
|
||||
|
||||
A command used to get a response once the command is processed. When several `inject` and `delay`
|
||||
commands are used in a row, the `sync` command can be used to track the progress of the command
|
||||
queue.
|
||||
|
||||
| Field | Type | Description |
|
||||
|:-----------:|:-------:|:---------------------------------------------|
|
||||
| `id` | integer | Device ID |
|
||||
| `command` | string | Must be set to "sync" |
|
||||
| `syncToken` | string | The token used to identify this sync command |
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
"id": 1,
|
||||
"command": "syncToken",
|
||||
"syncToken": "finished_injecting_events"
|
||||
}
|
||||
```
|
||||
|
||||
This command will result in the following response when it is processed:
|
||||
|
||||
```json5
|
||||
{
|
||||
"id": 1,
|
||||
"result": "sync",
|
||||
"syncToken": "finished_injecting_events"
|
||||
}
|
||||
```
|
||||
|
||||
### Notes
|
||||
1. As soon as EOF is reached (either in interactive mode, or in file mode),
|
||||
the device that was created will be unregistered. There is no
|
||||
|
||||
@@ -45,6 +45,7 @@ public class Device {
|
||||
private static final int MSG_OPEN_UINPUT_DEVICE = 1;
|
||||
private static final int MSG_CLOSE_UINPUT_DEVICE = 2;
|
||||
private static final int MSG_INJECT_EVENT = 3;
|
||||
private static final int MSG_SYNC_EVENT = 4;
|
||||
|
||||
private final int mId;
|
||||
private final HandlerThread mThread;
|
||||
@@ -118,6 +119,16 @@ public class Device {
|
||||
mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the uinput command queue by writing a sync response with the provided syncToken
|
||||
* to the output stream when this event is processed.
|
||||
*
|
||||
* @param syncToken The token for this sync command.
|
||||
*/
|
||||
public void syncEvent(String syncToken) {
|
||||
mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_SYNC_EVENT, syncToken), mTimeToSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close an uinput device.
|
||||
*
|
||||
@@ -171,6 +182,9 @@ public class Device {
|
||||
mCond.notify();
|
||||
}
|
||||
break;
|
||||
case MSG_SYNC_EVENT:
|
||||
handleSyncEvent((String) msg.obj);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown device message");
|
||||
}
|
||||
@@ -184,6 +198,18 @@ public class Device {
|
||||
getLooper().myQueue().removeSyncBarrier(mBarrierToken);
|
||||
mBarrierToken = 0;
|
||||
}
|
||||
|
||||
private void handleSyncEvent(String syncToken) {
|
||||
final JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("reason", "sync");
|
||||
json.put("id", mId);
|
||||
json.put("syncToken", syncToken);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException("Could not create JSON object ", e);
|
||||
}
|
||||
writeOutputObject(json);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeviceCallback {
|
||||
@@ -211,7 +237,7 @@ public class Device {
|
||||
}
|
||||
|
||||
public void onDeviceVibrating(int value) {
|
||||
JSONObject json = new JSONObject();
|
||||
final JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("reason", "vibrating");
|
||||
json.put("id", mId);
|
||||
@@ -219,12 +245,7 @@ public class Device {
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException("Could not create JSON object ", e);
|
||||
}
|
||||
try {
|
||||
mOutputStream.write(json.toString().getBytes());
|
||||
mOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
writeOutputObject(json);
|
||||
}
|
||||
|
||||
public void onDeviceError() {
|
||||
@@ -234,4 +255,13 @@ public class Device {
|
||||
msg.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOutputObject(JSONObject json) {
|
||||
try {
|
||||
mOutputStream.write(json.toString().getBytes());
|
||||
mOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ public class Event {
|
||||
enum Command {
|
||||
REGISTER("register"),
|
||||
DELAY("delay"),
|
||||
INJECT("inject");
|
||||
INJECT("inject"),
|
||||
SYNC("sync");
|
||||
|
||||
final String mCommandName;
|
||||
|
||||
@@ -77,6 +78,7 @@ public class Event {
|
||||
private int mFfEffectsMax = 0;
|
||||
private String mInputport;
|
||||
private SparseArray<InputAbsInfo> mAbsInfo;
|
||||
private String mSyncToken;
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
@@ -126,6 +128,10 @@ public class Event {
|
||||
return mInputport;
|
||||
}
|
||||
|
||||
public String getSyncToken() {
|
||||
return mSyncToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an event to String.
|
||||
*/
|
||||
@@ -206,6 +212,10 @@ public class Event {
|
||||
mEvent.mInputport = port;
|
||||
}
|
||||
|
||||
public void setSyncToken(String syncToken) {
|
||||
mEvent.mSyncToken = Objects.requireNonNull(syncToken, "Sync token must not be null");
|
||||
}
|
||||
|
||||
public Event build() {
|
||||
if (mEvent.mId == -1) {
|
||||
throw new IllegalStateException("No event id");
|
||||
@@ -225,10 +235,15 @@ public class Event {
|
||||
}
|
||||
}
|
||||
case INJECT -> {
|
||||
if (mEvent.mInjections == null) {
|
||||
if (mEvent.mInjections == null) {
|
||||
throw new IllegalStateException("Inject command is missing injection data");
|
||||
}
|
||||
}
|
||||
case SYNC -> {
|
||||
if (mEvent.mSyncToken == null) {
|
||||
throw new IllegalStateException("Sync command is missing sync token");
|
||||
}
|
||||
}
|
||||
}
|
||||
return mEvent;
|
||||
}
|
||||
@@ -295,6 +310,9 @@ public class Event {
|
||||
case "port":
|
||||
eb.setInputport(mReader.nextString());
|
||||
break;
|
||||
case "syncToken":
|
||||
eb.setSyncToken(mReader.nextString());
|
||||
break;
|
||||
default:
|
||||
mReader.skipValue();
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ public class Uinput {
|
||||
error("Device id=" + e.getId() + " is already registered. Ignoring event.");
|
||||
case INJECT -> d.injectEvent(e.getInjections());
|
||||
case DELAY -> d.addDelay(e.getDuration());
|
||||
case SYNC -> d.syncEvent(e.getSyncToken());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user