Implement single touch for custom vm
Bug: 331191129
Test: check if touch works
Change-Id: I485d9be6741165a9a03f55c96be50a5d64790d8d
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachine.java b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
index cc126eb..51b91ca 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachine.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
@@ -63,11 +63,13 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.view.MotionEvent;
import android.system.virtualizationcommon.DeathReason;
import android.system.virtualizationcommon.ErrorCode;
import android.system.virtualizationservice.IVirtualMachine;
import android.system.virtualizationservice.IVirtualMachineCallback;
import android.system.virtualizationservice.IVirtualizationService;
+import android.system.virtualizationservice.InputDevice;
import android.system.virtualizationservice.MemoryTrimLevel;
import android.system.virtualizationservice.PartitionType;
import android.system.virtualizationservice.VirtualMachineAppConfig;
@@ -79,6 +81,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.system.virtualmachine.flags.Flags;
+import libcore.io.IoBridge;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -89,6 +93,8 @@
import java.io.OutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileVisitResult;
@@ -154,6 +160,8 @@
@SuppressLint("MinMaxConstant") // Won't change: see man 7 vsock.
public static final long MAX_VSOCK_PORT = (1L << 32) - 1;
+ private ParcelFileDescriptor mTouchSock;
+
/**
* Status of a virtual machine
*
@@ -849,9 +857,73 @@
createVirtualMachineConfigForRawFrom(VirtualMachineConfig vmConfig)
throws IllegalStateException, IOException {
VirtualMachineRawConfig rawConfig = vmConfig.toVsRawConfig();
+
+ // Handle input devices here
+ List<InputDevice> inputDevices = new ArrayList<>();
+ if (vmConfig.getCustomImageConfig() != null
+ && vmConfig.getCustomImageConfig().useTouch()
+ && rawConfig.displayConfig != null) {
+ ParcelFileDescriptor[] pfds = ParcelFileDescriptor.createSocketPair();
+ mTouchSock = pfds[0];
+ InputDevice.SingleTouch t = new InputDevice.SingleTouch();
+ t.width = rawConfig.displayConfig.width;
+ t.height = rawConfig.displayConfig.height;
+ t.pfd = pfds[1];
+ inputDevices.add(InputDevice.singleTouch(t));
+ }
+ rawConfig.inputDevices = inputDevices.toArray(new InputDevice[0]);
+
return android.system.virtualizationservice.VirtualMachineConfig.rawConfig(rawConfig);
}
+ private void addInputEvent(ByteBuffer buffer, short type, short code, int value) {
+ buffer.putShort(type);
+ buffer.putShort(code);
+ buffer.putInt(value);
+ }
+
+ /** @hide */
+ public boolean sendSingleTouchEvent(MotionEvent event) {
+ if (mTouchSock == null) {
+ Log.d(TAG, "mTouchSock == null");
+ return false;
+ }
+ // from include/uapi/linux/input-event-codes.h in the kernel.
+ short EV_SYN = 0x00;
+ short EV_ABS = 0x03;
+ short EV_KEY = 0x01;
+ short BTN_TOUCH = 0x14a;
+ short ABS_X = 0x00;
+ short ABS_Y = 0x01;
+ short SYN_REPORT = 0x00;
+
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ boolean down = event.getAction() != MotionEvent.ACTION_UP;
+
+ ByteBuffer byteBuffer =
+ ByteBuffer.allocate(32 /* (type: u16 + code: u16 + value: i32) * 4 */);
+ byteBuffer.clear();
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ addInputEvent(byteBuffer, EV_ABS, ABS_X, x);
+ addInputEvent(byteBuffer, EV_ABS, ABS_Y, y);
+ addInputEvent(byteBuffer, EV_KEY, BTN_TOUCH, down ? 1 : 0);
+ addInputEvent(byteBuffer, EV_SYN, SYN_REPORT, 0);
+
+ try {
+ IoBridge.write(
+ mTouchSock.getFileDescriptor(),
+ byteBuffer.array(),
+ 0,
+ byteBuffer.array().length);
+ } catch (IOException e) {
+ Log.d(TAG, "cannot send touch evt", e);
+ return false;
+ }
+ return true;
+ }
+
private android.system.virtualizationservice.VirtualMachineConfig
createVirtualMachineConfigForAppFrom(
VirtualMachineConfig vmConfig, IVirtualizationService service)
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java b/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
index d267763..a8f318c 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -40,7 +40,6 @@
import android.sysprop.HypervisorProperties;
import android.system.virtualizationservice.DiskImage;
import android.system.virtualizationservice.Partition;
-import android.system.virtualizationservice.InputDevice;
import android.system.virtualizationservice.VirtualMachineAppConfig;
import android.system.virtualizationservice.VirtualMachinePayloadConfig;
import android.system.virtualizationservice.VirtualMachineRawConfig;
@@ -651,7 +650,6 @@
config.cpuTopology = (byte) this.mCpuTopology;
config.devices = EMPTY_STRING_ARRAY;
config.platformVersion = "~1.0";
- config.inputDevices = new InputDevice[0];
return config;
}
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java b/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
index 89df1f2..7cf5893 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
@@ -34,6 +34,7 @@
private static final String KEY_DISK_WRITABLES = "disk_writables";
private static final String KEY_DISK_IMAGES = "disk_images";
private static final String KEY_DISPLAY_CONFIG = "display_config";
+ private static final String KEY_TOUCH = "touch";
@Nullable private final String name;
@NonNull private final String kernelPath;
@@ -42,6 +43,7 @@
@Nullable private final String[] params;
@Nullable private final Disk[] disks;
@Nullable private final DisplayConfig displayConfig;
+ private final boolean touch;
@Nullable
public Disk[] getDisks() {
@@ -73,6 +75,10 @@
return params;
}
+ public boolean useTouch() {
+ return touch;
+ }
+
/** @hide */
public VirtualMachineCustomImageConfig(
String name,
@@ -81,7 +87,8 @@
String bootloaderPath,
String[] params,
Disk[] disks,
- DisplayConfig displayConfig) {
+ DisplayConfig displayConfig,
+ boolean touch) {
this.name = name;
this.kernelPath = kernelPath;
this.initrdPath = initrdPath;
@@ -89,6 +96,7 @@
this.params = params;
this.disks = disks;
this.displayConfig = displayConfig;
+ this.touch = touch;
}
static VirtualMachineCustomImageConfig from(PersistableBundle customImageConfigBundle) {
@@ -116,7 +124,7 @@
PersistableBundle displayConfigPb =
customImageConfigBundle.getPersistableBundle(KEY_DISPLAY_CONFIG);
builder.setDisplayConfig(DisplayConfig.from(displayConfigPb));
-
+ builder.useTouch(customImageConfigBundle.getBoolean(KEY_TOUCH));
return builder.build();
}
@@ -145,6 +153,7 @@
Optional.ofNullable(displayConfig)
.map(dc -> dc.toPersistableBundle())
.orElse(null));
+ pb.putBoolean(KEY_TOUCH, touch);
return pb;
}
@@ -193,6 +202,7 @@
private List<String> params = new ArrayList<>();
private List<Disk> disks = new ArrayList<>();
private DisplayConfig displayConfig;
+ private boolean touch;
/** @hide */
public Builder() {}
@@ -240,6 +250,12 @@
}
/** @hide */
+ public Builder useTouch(boolean touch) {
+ this.touch = touch;
+ return this;
+ }
+
+ /** @hide */
public VirtualMachineCustomImageConfig build() {
return new VirtualMachineCustomImageConfig(
this.name,
@@ -248,7 +264,8 @@
this.bootloaderPath,
this.params.toArray(new String[0]),
this.disks.toArray(new Disk[0]),
- displayConfig);
+ displayConfig,
+ touch);
}
}
diff --git a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
index b5995b8..450f4ed 100644
--- a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
+++ b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
@@ -126,6 +126,8 @@
}
customImageConfigBuilder.setDisplayConfig(displayConfigBuilder.build());
+ customImageConfigBuilder.useTouch(true);
+
configBuilder.setCustomImageConfig(customImageConfigBuilder.build());
} catch (JSONException | IOException e) {
@@ -224,6 +226,13 @@
}
SurfaceView surfaceView = findViewById(R.id.surface_view);
+ surfaceView.setOnTouchListener(
+ (v, event) -> {
+ if (mVirtualMachine == null) {
+ return false;
+ }
+ return mVirtualMachine.sendSingleTouchEvent(event);
+ });
surfaceView
.getHolder()
.addCallback(