Refactor wrappers for Android SDK classes

Internally, a failure to invoke a method via reflection was partially
managed using exceptions, partially using a null return value.

Handle all errors at the same place, by not catching
NoSuchMethodException too early.
This commit is contained in:
Romain Vimont 2019-11-27 22:05:25 +01:00
parent 525d6d4a75
commit bdd05b4a16
5 changed files with 57 additions and 112 deletions

View file

@ -22,31 +22,23 @@ public class ClipboardManager {
this.manager = manager; this.manager = manager;
} }
private Method getGetPrimaryClipMethod() { private Method getGetPrimaryClipMethod() throws NoSuchMethodException {
if (getPrimaryClipMethod == null) { if (getPrimaryClipMethod == null) {
try { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class);
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class); } else {
} else { getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class);
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class);
}
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
} }
} }
return getPrimaryClipMethod; return getPrimaryClipMethod;
} }
private Method getSetPrimaryClipMethod() { private Method getSetPrimaryClipMethod() throws NoSuchMethodException {
if (setPrimaryClipMethod == null) { if (setPrimaryClipMethod == null) {
try { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class);
setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class); } else {
} else { setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, int.class);
setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, int.class);
}
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
} }
} }
return setPrimaryClipMethod; return setPrimaryClipMethod;
@ -69,32 +61,26 @@ public class ClipboardManager {
} }
public CharSequence getText() { public CharSequence getText() {
Method method = getGetPrimaryClipMethod();
if (method == null) {
return null;
}
try { try {
Method method = getGetPrimaryClipMethod();
ClipData clipData = getPrimaryClip(method, manager); ClipData clipData = getPrimaryClip(method, manager);
if (clipData == null || clipData.getItemCount() == 0) { if (clipData == null || clipData.getItemCount() == 0) {
return null; return null;
} }
return clipData.getItemAt(0).getText(); return clipData.getItemAt(0).getText();
} catch (InvocationTargetException | IllegalAccessException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke " + method.getName(), e); Ln.e("Could not invoke method", e);
return null; return null;
} }
} }
public void setText(CharSequence text) { public void setText(CharSequence text) {
Method method = getSetPrimaryClipMethod();
if (method == null) {
return;
}
ClipData clipData = ClipData.newPlainText(null, text);
try { try {
Method method = getSetPrimaryClipMethod();
ClipData clipData = ClipData.newPlainText(null, text);
setPrimaryClip(method, manager, clipData); setPrimaryClip(method, manager, clipData);
} catch (InvocationTargetException | IllegalAccessException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke " + method.getName(), e); Ln.e("Could not invoke method", e);
} }
} }
} }

View file

@ -21,26 +21,19 @@ public final class InputManager {
this.manager = manager; this.manager = manager;
} }
private Method getInjectInputEventMethod() { private Method getInjectInputEventMethod() throws NoSuchMethodException {
if (injectInputEventMethod == null) { if (injectInputEventMethod == null) {
try { injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class);
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class);
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
}
} }
return injectInputEventMethod; return injectInputEventMethod;
} }
public boolean injectInputEvent(InputEvent inputEvent, int mode) { public boolean injectInputEvent(InputEvent inputEvent, int mode) {
Method method = getInjectInputEventMethod();
if (method == null) {
return false;
}
try { try {
return (Boolean) method.invoke(manager, inputEvent, mode); Method method = getInjectInputEventMethod();
} catch (InvocationTargetException | IllegalAccessException e) { return (boolean) method.invoke(manager, inputEvent, mode);
Ln.e("Could not invoke " + method.getName(), e); } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e);
return false; return false;
} }
} }

View file

@ -17,28 +17,21 @@ public final class PowerManager {
this.manager = manager; this.manager = manager;
} }
private Method getIsScreenOnMethod() { private Method getIsScreenOnMethod() throws NoSuchMethodException {
if (isScreenOnMethod == null) { if (isScreenOnMethod == null) {
try { @SuppressLint("ObsoleteSdkInt") // we may lower minSdkVersion in the future
@SuppressLint("ObsoleteSdkInt") // we may lower minSdkVersion in the future String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH ? "isInteractive" : "isScreenOn";
String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH ? "isInteractive" : "isScreenOn"; isScreenOnMethod = manager.getClass().getMethod(methodName);
isScreenOnMethod = manager.getClass().getMethod(methodName);
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
}
} }
return isScreenOnMethod; return isScreenOnMethod;
} }
public boolean isScreenOn() { public boolean isScreenOn() {
Method method = getIsScreenOnMethod();
if (method == null) {
return false;
}
try { try {
return (Boolean) method.invoke(manager); Method method = getIsScreenOnMethod();
} catch (InvocationTargetException | IllegalAccessException e) { return (boolean) method.invoke(manager);
Ln.e("Could not invoke " + method.getName(), e); } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e);
return false; return false;
} }
} }

View file

@ -17,49 +17,35 @@ public class StatusBarManager {
this.manager = manager; this.manager = manager;
} }
private Method getExpandNotificationsPanelMethod() { private Method getExpandNotificationsPanelMethod() throws NoSuchMethodException {
if (expandNotificationsPanelMethod == null) { if (expandNotificationsPanelMethod == null) {
try { expandNotificationsPanelMethod = manager.getClass().getMethod("expandNotificationsPanel");
expandNotificationsPanelMethod = manager.getClass().getMethod("expandNotificationsPanel");
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
}
} }
return expandNotificationsPanelMethod; return expandNotificationsPanelMethod;
} }
private Method getCollapsePanelsMethod() { private Method getCollapsePanelsMethod() throws NoSuchMethodException {
if (collapsePanelsMethod == null) { if (collapsePanelsMethod == null) {
try { collapsePanelsMethod = manager.getClass().getMethod("collapsePanels");
collapsePanelsMethod = manager.getClass().getMethod("collapsePanels");
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
}
} }
return collapsePanelsMethod; return collapsePanelsMethod;
} }
public void expandNotificationsPanel() { public void expandNotificationsPanel() {
Method method = getExpandNotificationsPanelMethod();
if (method == null) {
return;
}
try { try {
Method method = getExpandNotificationsPanelMethod();
method.invoke(manager); method.invoke(manager);
} catch (InvocationTargetException | IllegalAccessException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke " + method.getName(), e); Ln.e("Could not invoke method", e);
} }
} }
public void collapsePanels() { public void collapsePanels() {
Method method = getCollapsePanelsMethod();
if (method == null) {
return;
}
try { try {
Method method = getCollapsePanelsMethod();
method.invoke(manager); method.invoke(manager);
} catch (InvocationTargetException | IllegalAccessException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke " + method.getName(), e); Ln.e("Could not invoke method", e);
} }
} }
} }

View file

@ -84,29 +84,23 @@ public final class SurfaceControl {
} }
} }
private static Method getGetBuiltInDisplayMethod() { private static Method getGetBuiltInDisplayMethod() throws NoSuchMethodException {
if (getBuiltInDisplayMethod == null) { if (getBuiltInDisplayMethod == null) {
try { // the method signature has changed in Android Q
// the method signature has changed in Android Q // <https://github.com/Genymobile/scrcpy/issues/586>
// <https://github.com/Genymobile/scrcpy/issues/586> if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { getBuiltInDisplayMethod = CLASS.getMethod("getBuiltInDisplay", int.class);
getBuiltInDisplayMethod = CLASS.getMethod("getBuiltInDisplay", int.class); } else {
} else { getBuiltInDisplayMethod = CLASS.getMethod("getInternalDisplayToken");
getBuiltInDisplayMethod = CLASS.getMethod("getInternalDisplayToken");
}
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
} }
} }
return getBuiltInDisplayMethod; return getBuiltInDisplayMethod;
} }
public static IBinder getBuiltInDisplay() { public static IBinder getBuiltInDisplay() {
Method method = getGetBuiltInDisplayMethod();
if (method == null) {
return null;
}
try { try {
Method method = getGetBuiltInDisplayMethod();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// call getBuiltInDisplay(0) // call getBuiltInDisplay(0)
return (IBinder) method.invoke(null, 0); return (IBinder) method.invoke(null, 0);
@ -114,32 +108,25 @@ public final class SurfaceControl {
// call getInternalDisplayToken() // call getInternalDisplayToken()
return (IBinder) method.invoke(null); return (IBinder) method.invoke(null);
} catch (InvocationTargetException | IllegalAccessException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke " + method.getName(), e); Ln.e("Could not invoke method", e);
return null; return null;
} }
} }
private static Method getSetDisplayPowerModeMethod() { private static Method getSetDisplayPowerModeMethod() throws NoSuchMethodException {
if (setDisplayPowerModeMethod == null) { if (setDisplayPowerModeMethod == null) {
try { setDisplayPowerModeMethod = CLASS.getMethod("setDisplayPowerMode", IBinder.class, int.class);
setDisplayPowerModeMethod = CLASS.getMethod("setDisplayPowerMode", IBinder.class, int.class);
} catch (NoSuchMethodException e) {
Ln.e("Could not find method", e);
}
} }
return setDisplayPowerModeMethod; return setDisplayPowerModeMethod;
} }
public static void setDisplayPowerMode(IBinder displayToken, int mode) { public static void setDisplayPowerMode(IBinder displayToken, int mode) {
Method method = getSetDisplayPowerModeMethod();
if (method == null) {
return;
}
try { try {
Method method = getSetDisplayPowerModeMethod();
method.invoke(null, displayToken, mode); method.invoke(null, displayToken, mode);
} catch (InvocationTargetException | IllegalAccessException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke " + method.getName(), e); Ln.e("Could not invoke method", e);
} }
} }