diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java index 0c1777ecef..cb176cc3a9 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java @@ -16,9 +16,9 @@ public class ClipboardManager { private Method getPrimaryClipMethod; private Method setPrimaryClipMethod; private Method addPrimaryClipChangedListener; - private boolean alternativeGetMethod; - private boolean alternativeSetMethod; - private boolean alternativeAddListenerMethod; + private int getMethodVersion; + private int setMethodVersion; + private int addListenerMethodVersion; public ClipboardManager(IInterface manager) { this.manager = manager; @@ -31,9 +31,15 @@ private Method getGetPrimaryClipMethod() throws NoSuchMethodException { } else { try { getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class); - } catch (NoSuchMethodException e) { - getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, String.class, int.class); - alternativeGetMethod = true; + getMethodVersion = 0; + } catch (NoSuchMethodException e1) { + try { + getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, String.class, int.class); + getMethodVersion = 1; + } catch (NoSuchMethodException e2) { + getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, String.class, int.class, int.class); + getMethodVersion = 2; + } } } } @@ -47,41 +53,62 @@ private Method getSetPrimaryClipMethod() throws NoSuchMethodException { } else { try { setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, int.class); - } catch (NoSuchMethodException e) { - setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class); - alternativeSetMethod = true; + setMethodVersion = 0; + } catch (NoSuchMethodException e1) { + try { + setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class); + setMethodVersion = 1; + } catch (NoSuchMethodException e2) { + setPrimaryClipMethod = manager.getClass() + .getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class, int.class); + setMethodVersion = 2; + } } } } return setPrimaryClipMethod; } - private static ClipData getPrimaryClip(Method method, boolean alternativeMethod, IInterface manager) + private static ClipData getPrimaryClip(Method method, int methodVersion, IInterface manager) throws InvocationTargetException, IllegalAccessException { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME); } - if (alternativeMethod) { - return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID); + + switch (methodVersion) { + case 0: + return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID); + case 1: + return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID); + default: + return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0); } - return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID); } - private static void setPrimaryClip(Method method, boolean alternativeMethod, IInterface manager, ClipData clipData) + private static void setPrimaryClip(Method method, int methodVersion, IInterface manager, ClipData clipData) throws InvocationTargetException, IllegalAccessException { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { method.invoke(manager, clipData, FakeContext.PACKAGE_NAME); - } else if (alternativeMethod) { - method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID); - } else { - method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID); + return; + } + + switch (methodVersion) { + case 0: + method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID); + break; + case 1: + method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID); + break; + default: + method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0); + break; } } public CharSequence getText() { try { Method method = getGetPrimaryClipMethod(); - ClipData clipData = getPrimaryClip(method, alternativeGetMethod, manager); + ClipData clipData = getPrimaryClip(method, getMethodVersion, manager); if (clipData == null || clipData.getItemCount() == 0) { return null; } @@ -96,7 +123,7 @@ public boolean setText(CharSequence text) { try { Method method = getSetPrimaryClipMethod(); ClipData clipData = ClipData.newPlainText(null, text); - setPrimaryClip(method, alternativeSetMethod, manager, clipData); + setPrimaryClip(method, setMethodVersion, manager, clipData); return true; } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { Ln.e("Could not invoke method", e); @@ -104,14 +131,23 @@ public boolean setText(CharSequence text) { } } - private static void addPrimaryClipChangedListener(Method method, boolean alternativeMethod, IInterface manager, + private static void addPrimaryClipChangedListener(Method method, int methodVersion, IInterface manager, IOnPrimaryClipChangedListener listener) throws InvocationTargetException, IllegalAccessException { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { method.invoke(manager, listener, FakeContext.PACKAGE_NAME); - } else if (alternativeMethod) { - method.invoke(manager, listener, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID); - } else { - method.invoke(manager, listener, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID); + return; + } + + switch (methodVersion) { + case 0: + method.invoke(manager, listener, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID); + break; + case 1: + method.invoke(manager, listener, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID); + break; + default: + method.invoke(manager, listener, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0); + break; } } @@ -124,10 +160,19 @@ private Method getAddPrimaryClipChangedListener() throws NoSuchMethodException { try { addPrimaryClipChangedListener = manager.getClass() .getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class, int.class); - } catch (NoSuchMethodException e) { - addPrimaryClipChangedListener = manager.getClass() - .getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class, String.class, int.class); - alternativeAddListenerMethod = true; + addListenerMethodVersion = 0; + } catch (NoSuchMethodException e1) { + try { + addPrimaryClipChangedListener = manager.getClass() + .getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class, String.class, + int.class); + addListenerMethodVersion = 1; + } catch (NoSuchMethodException e2) { + addPrimaryClipChangedListener = manager.getClass() + .getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class, String.class, + int.class, int.class); + addListenerMethodVersion = 2; + } } } } @@ -137,7 +182,7 @@ private Method getAddPrimaryClipChangedListener() throws NoSuchMethodException { public boolean addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) { try { Method method = getAddPrimaryClipChangedListener(); - addPrimaryClipChangedListener(method, alternativeAddListenerMethod, manager, listener); + addPrimaryClipChangedListener(method, addListenerMethodVersion, manager, listener); return true; } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { Ln.e("Could not invoke method", e); diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java index 32bf42527b..ef0a4f508d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java @@ -14,13 +14,13 @@ public final class InputManager { public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1; public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; - private final android.hardware.input.InputManager manager; + private final Object manager; private Method injectInputEventMethod; private static Method setDisplayIdMethod; private static Method setActionButtonMethod; - public InputManager(android.hardware.input.InputManager manager) { + public InputManager(Object manager) { this.manager = manager; } diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java index ee2f0fa978..74d85dfb63 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java @@ -3,6 +3,7 @@ import android.annotation.SuppressLint; import android.os.IBinder; import android.os.IInterface; +import com.genymobile.scrcpy.Ln; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -65,9 +66,19 @@ public static DisplayManager getDisplayManager() { public static InputManager getInputManager() { if (inputManager == null) { try { - Method getInstanceMethod = android.hardware.input.InputManager.class.getDeclaredMethod("getInstance"); - android.hardware.input.InputManager im = (android.hardware.input.InputManager) getInstanceMethod.invoke(null); - inputManager = new InputManager(im); + try { + Object im = Class.forName("android.hardware.input.InputManagerGlobal") + .getMethod("getInstance").invoke(null); + Ln.i("Using the InputManagerGlobal API"); + inputManager = new InputManager(im); + } catch (ClassNotFoundException e) { + Method getInstanceMethod = android.hardware.input.InputManager.class + .getDeclaredMethod("getInstance"); + android.hardware.input.InputManager im = + (android.hardware.input.InputManager) getInstanceMethod.invoke(null); + Ln.i("Fallback to the legacy InputManager control API."); + inputManager = new InputManager(im); + } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { throw new AssertionError(e); }