Make ServiceManager and Settings methods static

There were exactly one instance of ServiceManager and Settings, stored
in Device.

Since a Device instance is not created by the CleanUp executable, it was
not straightforward to call wrapper methods on cleanup.

Remove this artificial restriction and expose them publicly via static
methods (this is equivalent to expose a singleton, but less verbose).
This commit is contained in:
Romain Vimont 2022-10-02 17:39:23 +02:00
parent 7505f7117e
commit 40644994e8
5 changed files with 49 additions and 60 deletions

View file

@ -1,7 +1,5 @@
package com.genymobile.scrcpy; package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.ServiceManager;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.Base64; import android.util.Base64;
@ -164,12 +162,10 @@ public final class CleanUp {
Config config = Config.fromBase64(args[0]); Config config = Config.fromBase64(args[0]);
if (config.disableShowTouches || config.restoreStayOn != -1) { if (config.disableShowTouches || config.restoreStayOn != -1) {
ServiceManager serviceManager = new ServiceManager();
Settings settings = new Settings(serviceManager);
if (config.disableShowTouches) { if (config.disableShowTouches) {
Ln.i("Disabling \"show touches\""); Ln.i("Disabling \"show touches\"");
try { try {
settings.putValue(Settings.TABLE_SYSTEM, "show_touches", "0"); Settings.putValue(Settings.TABLE_SYSTEM, "show_touches", "0");
} catch (SettingsException e) { } catch (SettingsException e) {
Ln.e("Could not restore \"show_touches\"", e); Ln.e("Could not restore \"show_touches\"", e);
} }
@ -177,7 +173,7 @@ public final class CleanUp {
if (config.restoreStayOn != -1) { if (config.restoreStayOn != -1) {
Ln.i("Restoring \"stay awake\""); Ln.i("Restoring \"stay awake\"");
try { try {
settings.putValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(config.restoreStayOn)); Settings.putValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(config.restoreStayOn));
} catch (SettingsException e) { } catch (SettingsException e) {
Ln.e("Could not restore \"stay_on_while_plugged_in\"", e); Ln.e("Could not restore \"stay_on_while_plugged_in\"", e);
} }

View file

@ -31,9 +31,6 @@ public final class Device {
public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1; public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1;
public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2; public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2;
private static final ServiceManager SERVICE_MANAGER = new ServiceManager();
private static final Settings SETTINGS = new Settings(SERVICE_MANAGER);
public interface RotationListener { public interface RotationListener {
void onRotationChanged(int rotation); void onRotationChanged(int rotation);
} }
@ -66,9 +63,9 @@ public final class Device {
public Device(Options options) { public Device(Options options) {
displayId = options.getDisplayId(); displayId = options.getDisplayId();
DisplayInfo displayInfo = SERVICE_MANAGER.getDisplayManager().getDisplayInfo(displayId); DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
if (displayInfo == null) { if (displayInfo == null) {
int[] displayIds = SERVICE_MANAGER.getDisplayManager().getDisplayIds(); int[] displayIds = ServiceManager.getDisplayManager().getDisplayIds();
throw new InvalidDisplayIdException(displayId, displayIds); throw new InvalidDisplayIdException(displayId, displayIds);
} }
@ -82,7 +79,7 @@ public final class Device {
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation); screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation);
layerStack = displayInfo.getLayerStack(); layerStack = displayInfo.getLayerStack();
SERVICE_MANAGER.getWindowManager().registerRotationWatcher(new IRotationWatcher.Stub() { ServiceManager.getWindowManager().registerRotationWatcher(new IRotationWatcher.Stub() {
@Override @Override
public void onRotationChanged(int rotation) { public void onRotationChanged(int rotation) {
synchronized (Device.this) { synchronized (Device.this) {
@ -98,7 +95,7 @@ public final class Device {
if (options.getControl() && options.getClipboardAutosync()) { if (options.getControl() && options.getClipboardAutosync()) {
// If control and autosync are enabled, synchronize Android clipboard to the computer automatically // If control and autosync are enabled, synchronize Android clipboard to the computer automatically
ClipboardManager clipboardManager = SERVICE_MANAGER.getClipboardManager(); ClipboardManager clipboardManager = ServiceManager.getClipboardManager();
if (clipboardManager != null) { if (clipboardManager != null) {
clipboardManager.addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() { clipboardManager.addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() {
@Override @Override
@ -192,7 +189,7 @@ public final class Device {
return false; return false;
} }
return SERVICE_MANAGER.getInputManager().injectInputEvent(inputEvent, injectMode); return ServiceManager.getInputManager().injectInputEvent(inputEvent, injectMode);
} }
public boolean injectEvent(InputEvent event, int injectMode) { public boolean injectEvent(InputEvent event, int injectMode) {
@ -220,7 +217,7 @@ public final class Device {
} }
public static boolean isScreenOn() { public static boolean isScreenOn() {
return SERVICE_MANAGER.getPowerManager().isScreenOn(); return ServiceManager.getPowerManager().isScreenOn();
} }
public synchronized void setRotationListener(RotationListener rotationListener) { public synchronized void setRotationListener(RotationListener rotationListener) {
@ -232,19 +229,19 @@ public final class Device {
} }
public static void expandNotificationPanel() { public static void expandNotificationPanel() {
SERVICE_MANAGER.getStatusBarManager().expandNotificationsPanel(); ServiceManager.getStatusBarManager().expandNotificationsPanel();
} }
public static void expandSettingsPanel() { public static void expandSettingsPanel() {
SERVICE_MANAGER.getStatusBarManager().expandSettingsPanel(); ServiceManager.getStatusBarManager().expandSettingsPanel();
} }
public static void collapsePanels() { public static void collapsePanels() {
SERVICE_MANAGER.getStatusBarManager().collapsePanels(); ServiceManager.getStatusBarManager().collapsePanels();
} }
public static String getClipboardText() { public static String getClipboardText() {
ClipboardManager clipboardManager = SERVICE_MANAGER.getClipboardManager(); ClipboardManager clipboardManager = ServiceManager.getClipboardManager();
if (clipboardManager == null) { if (clipboardManager == null) {
return null; return null;
} }
@ -256,7 +253,7 @@ public final class Device {
} }
public boolean setClipboardText(String text) { public boolean setClipboardText(String text) {
ClipboardManager clipboardManager = SERVICE_MANAGER.getClipboardManager(); ClipboardManager clipboardManager = ServiceManager.getClipboardManager();
if (clipboardManager == null) { if (clipboardManager == null) {
return false; return false;
} }
@ -299,7 +296,7 @@ public final class Device {
* Disable auto-rotation (if enabled), set the screen rotation and re-enable auto-rotation (if it was enabled). * Disable auto-rotation (if enabled), set the screen rotation and re-enable auto-rotation (if it was enabled).
*/ */
public static void rotateDevice() { public static void rotateDevice() {
WindowManager wm = SERVICE_MANAGER.getWindowManager(); WindowManager wm = ServiceManager.getWindowManager();
boolean accelerometerRotation = !wm.isRotationFrozen(); boolean accelerometerRotation = !wm.isRotationFrozen();
@ -315,8 +312,4 @@ public final class Device {
wm.thawRotation(); wm.thawRotation();
} }
} }
public static Settings getSettings() {
return SETTINGS;
}
} }

View file

@ -20,10 +20,9 @@ public final class Server {
int restoreStayOn = -1; int restoreStayOn = -1;
boolean restoreNormalPowerMode = options.getControl(); // only restore power mode if control is enabled boolean restoreNormalPowerMode = options.getControl(); // only restore power mode if control is enabled
if (options.getShowTouches() || options.getStayAwake()) { if (options.getShowTouches() || options.getStayAwake()) {
Settings settings = Device.getSettings();
if (options.getShowTouches()) { if (options.getShowTouches()) {
try { try {
String oldValue = settings.getAndPutValue(Settings.TABLE_SYSTEM, "show_touches", "1"); String oldValue = Settings.getAndPutValue(Settings.TABLE_SYSTEM, "show_touches", "1");
// If "show touches" was disabled, it must be disabled back on clean up // If "show touches" was disabled, it must be disabled back on clean up
mustDisableShowTouchesOnCleanUp = !"1".equals(oldValue); mustDisableShowTouchesOnCleanUp = !"1".equals(oldValue);
} catch (SettingsException e) { } catch (SettingsException e) {
@ -34,7 +33,7 @@ public final class Server {
if (options.getStayAwake()) { if (options.getStayAwake()) {
int stayOn = BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS; int stayOn = BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS;
try { try {
String oldValue = settings.getAndPutValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(stayOn)); String oldValue = Settings.getAndPutValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(stayOn));
try { try {
restoreStayOn = Integer.parseInt(oldValue); restoreStayOn = Integer.parseInt(oldValue);
if (restoreStayOn == stayOn) { if (restoreStayOn == stayOn) {

View file

@ -7,16 +7,14 @@ import android.os.Build;
import java.io.IOException; import java.io.IOException;
public class Settings { public final class Settings {
public static final String TABLE_SYSTEM = ContentProvider.TABLE_SYSTEM; public static final String TABLE_SYSTEM = ContentProvider.TABLE_SYSTEM;
public static final String TABLE_SECURE = ContentProvider.TABLE_SECURE; public static final String TABLE_SECURE = ContentProvider.TABLE_SECURE;
public static final String TABLE_GLOBAL = ContentProvider.TABLE_GLOBAL; public static final String TABLE_GLOBAL = ContentProvider.TABLE_GLOBAL;
private final ServiceManager serviceManager; private Settings() {
/* not instantiable */
public Settings(ServiceManager serviceManager) {
this.serviceManager = serviceManager;
} }
private static void execSettingsPut(String table, String key, String value) throws SettingsException { private static void execSettingsPut(String table, String key, String value) throws SettingsException {
@ -35,10 +33,10 @@ public class Settings {
} }
} }
public String getValue(String table, String key) throws SettingsException { public static String getValue(String table, String key) throws SettingsException {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
// on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788> // on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788>
try (ContentProvider provider = serviceManager.getActivityManager().createSettingsProvider()) { try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
return provider.getValue(table, key); return provider.getValue(table, key);
} catch (SettingsException e) { } catch (SettingsException e) {
Ln.w("Could not get settings value via ContentProvider, fallback to settings process", e); Ln.w("Could not get settings value via ContentProvider, fallback to settings process", e);
@ -48,10 +46,10 @@ public class Settings {
return execSettingsGet(table, key); return execSettingsGet(table, key);
} }
public void putValue(String table, String key, String value) throws SettingsException { public static void putValue(String table, String key, String value) throws SettingsException {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
// on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788> // on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788>
try (ContentProvider provider = serviceManager.getActivityManager().createSettingsProvider()) { try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
provider.putValue(table, key, value); provider.putValue(table, key, value);
} catch (SettingsException e) { } catch (SettingsException e) {
Ln.w("Could not put settings value via ContentProvider, fallback to settings process", e); Ln.w("Could not put settings value via ContentProvider, fallback to settings process", e);
@ -61,10 +59,10 @@ public class Settings {
execSettingsPut(table, key, value); execSettingsPut(table, key, value);
} }
public String getAndPutValue(String table, String key, String value) throws SettingsException { public static String getAndPutValue(String table, String key, String value) throws SettingsException {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
// on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788> // on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788>
try (ContentProvider provider = serviceManager.getActivityManager().createSettingsProvider()) { try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
String oldValue = provider.getValue(table, key); String oldValue = provider.getValue(table, key);
if (!value.equals(oldValue)) { if (!value.equals(oldValue)) {
provider.putValue(table, key, value); provider.putValue(table, key, value);

View file

@ -13,27 +13,30 @@ public final class ServiceManager {
public static final String PACKAGE_NAME = "com.android.shell"; public static final String PACKAGE_NAME = "com.android.shell";
public static final int USER_ID = 0; public static final int USER_ID = 0;
private final Method getServiceMethod; private static final Method GET_SERVICE_METHOD;
static {
private WindowManager windowManager;
private DisplayManager displayManager;
private InputManager inputManager;
private PowerManager powerManager;
private StatusBarManager statusBarManager;
private ClipboardManager clipboardManager;
private ActivityManager activityManager;
public ServiceManager() {
try { try {
getServiceMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class); GET_SERVICE_METHOD = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class);
} catch (Exception e) { } catch (Exception e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
private IInterface getService(String service, String type) { private static WindowManager windowManager;
private static DisplayManager displayManager;
private static InputManager inputManager;
private static PowerManager powerManager;
private static StatusBarManager statusBarManager;
private static ClipboardManager clipboardManager;
private static ActivityManager activityManager;
private ServiceManager() {
/* not instantiable */
}
private static IInterface getService(String service, String type) {
try { try {
IBinder binder = (IBinder) getServiceMethod.invoke(null, service); IBinder binder = (IBinder) GET_SERVICE_METHOD.invoke(null, service);
Method asInterfaceMethod = Class.forName(type + "$Stub").getMethod("asInterface", IBinder.class); Method asInterfaceMethod = Class.forName(type + "$Stub").getMethod("asInterface", IBinder.class);
return (IInterface) asInterfaceMethod.invoke(null, binder); return (IInterface) asInterfaceMethod.invoke(null, binder);
} catch (Exception e) { } catch (Exception e) {
@ -41,14 +44,14 @@ public final class ServiceManager {
} }
} }
public WindowManager getWindowManager() { public static WindowManager getWindowManager() {
if (windowManager == null) { if (windowManager == null) {
windowManager = new WindowManager(getService("window", "android.view.IWindowManager")); windowManager = new WindowManager(getService("window", "android.view.IWindowManager"));
} }
return windowManager; return windowManager;
} }
public DisplayManager getDisplayManager() { public static DisplayManager getDisplayManager() {
if (displayManager == null) { if (displayManager == null) {
try { try {
Class<?> clazz = Class.forName("android.hardware.display.DisplayManagerGlobal"); Class<?> clazz = Class.forName("android.hardware.display.DisplayManagerGlobal");
@ -62,7 +65,7 @@ public final class ServiceManager {
return displayManager; return displayManager;
} }
public InputManager getInputManager() { public static InputManager getInputManager() {
if (inputManager == null) { if (inputManager == null) {
try { try {
Method getInstanceMethod = android.hardware.input.InputManager.class.getDeclaredMethod("getInstance"); Method getInstanceMethod = android.hardware.input.InputManager.class.getDeclaredMethod("getInstance");
@ -75,21 +78,21 @@ public final class ServiceManager {
return inputManager; return inputManager;
} }
public PowerManager getPowerManager() { public static PowerManager getPowerManager() {
if (powerManager == null) { if (powerManager == null) {
powerManager = new PowerManager(getService("power", "android.os.IPowerManager")); powerManager = new PowerManager(getService("power", "android.os.IPowerManager"));
} }
return powerManager; return powerManager;
} }
public StatusBarManager getStatusBarManager() { public static StatusBarManager getStatusBarManager() {
if (statusBarManager == null) { if (statusBarManager == null) {
statusBarManager = new StatusBarManager(getService("statusbar", "com.android.internal.statusbar.IStatusBarService")); statusBarManager = new StatusBarManager(getService("statusbar", "com.android.internal.statusbar.IStatusBarService"));
} }
return statusBarManager; return statusBarManager;
} }
public ClipboardManager getClipboardManager() { public static ClipboardManager getClipboardManager() {
if (clipboardManager == null) { if (clipboardManager == null) {
IInterface clipboard = getService("clipboard", "android.content.IClipboard"); IInterface clipboard = getService("clipboard", "android.content.IClipboard");
if (clipboard == null) { if (clipboard == null) {
@ -103,7 +106,7 @@ public final class ServiceManager {
return clipboardManager; return clipboardManager;
} }
public ActivityManager getActivityManager() { public static ActivityManager getActivityManager() {
if (activityManager == null) { if (activityManager == null) {
try { try {
// On old Android versions, the ActivityManager is not exposed via AIDL, // On old Android versions, the ActivityManager is not exposed via AIDL,