Set tablet mode if there is a physical keyboard

and also virtual keyboard shows

Bug: 353823512
Test: attach and detach a physical keyboard, and check UI style and
virtual keyboard

Change-Id: I06c3fa209cf312c7299f9a726c4b7c40b78b2ce5
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachine.java b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
index b6de9bb..a51f7e1 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachine.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
@@ -1192,6 +1192,25 @@
     }
 
     /** @hide */
+    public boolean sendTabletModeEvent(boolean tabletMode) {
+        if (mSwitchesSock == null) {
+            Log.d(TAG, "mSwitcheSock == null");
+            return false;
+        }
+
+        // from include/uapi/linux/input-event-codes.h in the kernel.
+        short EV_SYN = 0x00;
+        short EV_SW = 0x05;
+        short SW_TABLET_MODE = 0x01;
+        short SYN_REPORT = 0x00;
+        return writeEventsToSock(
+                mSwitchesSock,
+                Arrays.asList(
+                        new InputEvent(EV_SW, SW_TABLET_MODE, tabletMode ? 1 : 0),
+                        new InputEvent(EV_SYN, SYN_REPORT, 0)));
+    }
+
+    /** @hide */
     public boolean sendTrackpadEvent(MotionEvent event) {
         try {
             mInputEventQueue.add(Pair.create(InputEventType.TRACKPAD, event));
diff --git a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
index 8bb0fd4..694aa57 100644
--- a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
+++ b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
@@ -28,6 +28,7 @@
 import android.crosvm.ICrosvmAndroidDisplayService;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.hardware.input.InputManager;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -77,7 +78,7 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-public class MainActivity extends Activity {
+public class MainActivity extends Activity implements InputManager.InputDeviceListener {
     private static final String TAG = "VmLauncherApp";
     private static final String VM_NAME = "my_custom_vm";
     private static final boolean DEBUG = true;
@@ -256,6 +257,56 @@
         return !isVolumeKey(keyCode) && mVirtualMachine.sendKeyEvent(event);
     }
 
+    private void registerInputDeviceListener() {
+        InputManager inputManager = getSystemService(InputManager.class);
+        if (inputManager == null) {
+            Log.e(TAG, "failed to registerInputDeviceListener because InputManager is null");
+            return;
+        }
+        inputManager.registerInputDeviceListener(this, null);
+    }
+
+    private void unregisterInputDeviceListener() {
+        InputManager inputManager = getSystemService(InputManager.class);
+        if (inputManager == null) {
+            Log.e(TAG, "failed to unregisterInputDeviceListener because InputManager is null");
+            return;
+        }
+        inputManager.unregisterInputDeviceListener(this);
+    }
+
+    private void setTabletModeConditionally() {
+        if (mVirtualMachine == null) {
+            Log.e(TAG, "failed to setTabletModeConditionally because VirtualMachine is null");
+            return;
+        }
+        for (int id : InputDevice.getDeviceIds()) {
+            InputDevice d = InputDevice.getDevice(id);
+            if (!d.isVirtual() && d.isEnabled() && d.isFullKeyboard()) {
+                Log.d(TAG, "the device has a physical keyboard, turn off tablet mode");
+                mVirtualMachine.sendTabletModeEvent(false);
+                return;
+            }
+        }
+        mVirtualMachine.sendTabletModeEvent(true);
+        Log.d(TAG, "the device doesn't have a physical keyboard, turn on tablet mode");
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        setTabletModeConditionally();
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        setTabletModeConditionally();
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        setTabletModeConditionally();
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -460,6 +511,13 @@
         windowInsetsController.setSystemBarsBehavior(
                 WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
         windowInsetsController.hide(WindowInsets.Type.systemBars());
+        registerInputDeviceListener();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        setTabletModeConditionally();
     }
 
     @Override
@@ -494,6 +552,7 @@
         if (mExecutorService != null) {
             mExecutorService.shutdownNow();
         }
+        unregisterInputDeviceListener();
         Log.d(TAG, "destroyed");
     }