Apply Genymobile rules for Android projects

Apply Genymobile checkstyle and gradle build files organization.
This commit is contained in:
Romain Vimont 2018-02-07 18:06:23 +01:00
commit e55e42a442
19 changed files with 299 additions and 52 deletions

View file

@ -1,11 +1,11 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
compileSdkVersion 27
defaultConfig {
applicationId "com.genymobile.scrcpy"
minSdkVersion 21
targetSdkVersion 26
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@ -22,3 +22,5 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
}
apply from: "$project.rootDir/config/android-checkstyle.gradle"

View file

@ -3,7 +3,7 @@ package com.genymobile.scrcpy;
/**
* Union of all supported event types, identified by their {@code type}.
*/
public class ControlEvent {
public final class ControlEvent {
public static final int TYPE_KEYCODE = 0;
public static final int TYPE_TEXT = 1;

View file

@ -12,9 +12,12 @@ public class ControlEventReader {
private static final int SCROLL_PAYLOAD_LENGTH = 16;
private static final int COMMAND_PAYLOAD_LENGTH = 1;
private final byte[] rawBuffer = new byte[128];
private static final int MAX_TEXT_LENGTH = 32;
private static final int RAW_BUFFER_SIZE = 128;
private final byte[] rawBuffer = new byte[RAW_BUFFER_SIZE];
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
private final byte[] textBuffer = new byte[32];
private final byte[] textBuffer = new byte[MAX_TEXT_LENGTH];
public ControlEventReader() {
// invariant: the buffer is always in "get" mode
@ -136,10 +139,12 @@ public class ControlEventReader {
return new Position(x, y, screenWidth, screenHeight);
}
@SuppressWarnings("checkstyle:MagicNumber")
private static int toUnsigned(short value) {
return value & 0xffff;
}
@SuppressWarnings("checkstyle:MagicNumber")
private static int toUnsigned(byte value) {
return value & 0xff;
}

View file

@ -9,7 +9,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class DesktopConnection implements Closeable {
public final class DesktopConnection implements Closeable {
private static final int DEVICE_NAME_FIELD_LENGTH = 64;
@ -48,9 +48,8 @@ public class DesktopConnection implements Closeable {
socket.close();
}
@SuppressWarnings("checkstyle:MagicNumber")
private void send(String deviceName, int width, int height) throws IOException {
assert width < 0x10000 : "width may not be stored on 16 bits";
assert height < 0x10000 : "height may not be stored on 16 bits";
byte[] buffer = new byte[DEVICE_NAME_FIELD_LENGTH + 4];
byte[] deviceNameBytes = deviceName.getBytes(StandardCharsets.UTF_8);

View file

@ -1,13 +1,13 @@
package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.ServiceManager;
import android.graphics.Point;
import android.os.Build;
import android.os.RemoteException;
import android.view.IRotationWatcher;
import android.view.InputEvent;
import com.genymobile.scrcpy.wrappers.ServiceManager;
public final class Device {
public interface RotationListener {
@ -40,6 +40,7 @@ public final class Device {
return screenInfo;
}
@SuppressWarnings("checkstyle:MagicNumber")
private ScreenInfo computeScreenInfo(int maxSize) {
// Compute the video size and the padding of the content inside this video.
// Principle:
@ -52,7 +53,9 @@ public final class Device {
int w = deviceSize.getWidth();
int h = deviceSize.getHeight();
if (maxSize > 0) {
assert maxSize % 8 == 0;
if (BuildConfig.DEBUG && maxSize % 8 != 0) {
throw new AssertionError("Max size must be a multiple of 8");
}
boolean portrait = h > w;
int major = portrait ? h : w;
int minor = portrait ? w : h;
@ -70,6 +73,7 @@ public final class Device {
}
public Point getPhysicalPoint(Position position) {
@SuppressWarnings("checkstyle:HiddenField") // it hides the field on purpose, to read it with a lock
ScreenInfo screenInfo = getScreenInfo(); // read with synchronization
Size videoSize = screenInfo.getVideoSize();
Size clientVideoSize = position.getScreenSize();

View file

@ -1,5 +1,7 @@
package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.InputManager;
import android.graphics.Point;
import android.os.SystemClock;
import android.view.InputDevice;
@ -8,10 +10,9 @@ import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import com.genymobile.scrcpy.wrappers.InputManager;
import java.io.IOException;
public class EventController {
private final Device device;
@ -83,6 +84,8 @@ public class EventController {
case ControlEvent.TYPE_COMMAND:
executeCommand(controlEvent.getAction());
break;
default:
// do nothing
}
}
@ -157,6 +160,8 @@ public class EventController {
switch (action) {
case ControlEvent.COMMAND_SCREEN_ON:
return turnScreenOn();
default:
Ln.w("Unsupported command: " + action);
}
return false;
}

View file

@ -6,7 +6,7 @@ import android.util.Log;
* Log both to Android logger (so that logs are visible in "adb logcat") and standard output/error (so that they are visible in the terminal
* directly).
*/
public class Ln {
public final class Ln {
private static final String TAG = "scrcpy";

View file

@ -27,11 +27,15 @@ public class Position {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Position position = (Position) o;
return Objects.equals(point, position.point) &&
Objects.equals(screenSize, position.screenSize);
return Objects.equals(point, position.point)
&& Objects.equals(screenSize, position.screenSize);
}
@Override
@ -41,10 +45,10 @@ public class Position {
@Override
public String toString() {
return "Position{" +
"point=" + point +
", screenSize=" + screenSize +
'}';
return "Position{"
+ "point=" + point
+ ", screenSize=" + screenSize
+ '}';
}
}

View file

@ -2,7 +2,11 @@ package com.genymobile.scrcpy;
import java.io.IOException;
public class ScrCpyServer {
public final class ScrCpyServer {
private ScrCpyServer() {
// not instantiable
}
private static void scrcpy(Options options) throws IOException {
final Device device = new Device(options);
@ -34,6 +38,7 @@ public class ScrCpyServer {
}).start();
}
@SuppressWarnings("checkstyle:MagicNumber")
private static Options createOptions(String... args) {
Options options = new Options();
if (args.length < 1) {

View file

@ -1,5 +1,7 @@
package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.SurfaceControl;
import android.graphics.Rect;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
@ -7,8 +9,6 @@ import android.media.MediaFormat;
import android.os.IBinder;
import android.view.Surface;
import com.genymobile.scrcpy.wrappers.SurfaceControl;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
@ -22,6 +22,8 @@ public class ScreenEncoder implements Device.RotationListener {
private static final int REPEAT_FRAME_DELAY = 6; // repeat after 6 frames
private static final int MICROSECONDS_IN_ONE_SECOND = 1_000_000;
private final AtomicBoolean rotationChanged = new AtomicBoolean();
private int bitRate;
@ -81,6 +83,7 @@ public class ScreenEncoder implements Device.RotationListener {
}
private boolean encode(MediaCodec codec, OutputStream outputStream) throws IOException {
@SuppressWarnings("checkstyle:MagicNumber")
byte[] buf = new byte[bitRate / 8]; // may contain up to 1 second of video
boolean eof = false;
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
@ -124,7 +127,7 @@ public class ScreenEncoder implements Device.RotationListener {
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
// display the very first frame, and recover from bad quality when no new frames
format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1_000_000 * REPEAT_FRAME_DELAY / frameRate); // µs
format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, MICROSECONDS_IN_ONE_SECOND * REPEAT_FRAME_DELAY / frameRate); // µs
return format;
}

View file

@ -31,11 +31,15 @@ public final class Size {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Size size = (Size) o;
return width == size.width &&
height == size.height;
return width == size.width
&& height == size.height;
}
@Override
@ -45,9 +49,9 @@ public final class Size {
@Override
public String toString() {
return "Size{" +
"width=" + width +
", height=" + height +
'}';
return "Size{"
+ "width=" + width
+ ", height=" + height
+ '}';
}
}

View file

@ -1,11 +1,11 @@
package com.genymobile.scrcpy.wrappers;
import android.os.IInterface;
import com.genymobile.scrcpy.DisplayInfo;
import com.genymobile.scrcpy.Size;
public class DisplayManager {
import android.os.IInterface;
public final class DisplayManager {
private final IInterface manager;
public DisplayManager(IInterface manager) {

View file

@ -6,7 +6,7 @@ import android.view.InputEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class InputManager {
public final class InputManager {
public static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0;
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1;

View file

@ -1,19 +1,21 @@
package com.genymobile.scrcpy.wrappers;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.IInterface;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class PowerManager {
public final class PowerManager {
private final IInterface manager;
private final Method isScreenOnMethod;
public PowerManager(IInterface manager) {
this.manager = manager;
try {
String methodName = Build.VERSION.SDK_INT >= 20 ? "isInteractive" : "isScreenOn";
@SuppressLint("ObsoleteSdkInt") // we may lower minSdkVersion in the future
String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH ? "isInteractive" : "isScreenOn";
isScreenOnMethod = manager.getClass().getMethod(methodName);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);

View file

@ -1,11 +1,13 @@
package com.genymobile.scrcpy.wrappers;
import android.annotation.SuppressLint;
import android.os.IBinder;
import android.os.IInterface;
import java.lang.reflect.Method;
public class ServiceManager {
@SuppressLint("PrivateApi")
public final class ServiceManager {
private final Method getServiceMethod;
private WindowManager windowManager;

View file

@ -1,16 +1,18 @@
package com.genymobile.scrcpy.wrappers;
import android.annotation.SuppressLint;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.Surface;
public class SurfaceControl {
@SuppressLint("PrivateApi")
public final class SurfaceControl {
private static final Class<?> cls;
private static final Class<?> CLASS;
static {
try {
cls = Class.forName("android.view.SurfaceControl");
CLASS = Class.forName("android.view.SurfaceControl");
} catch (ClassNotFoundException e) {
throw new AssertionError(e);
}
@ -22,7 +24,7 @@ public class SurfaceControl {
public static void openTransaction() {
try {
cls.getMethod("openTransaction").invoke(null);
CLASS.getMethod("openTransaction").invoke(null);
} catch (Exception e) {
throw new AssertionError(e);
}
@ -30,7 +32,7 @@ public class SurfaceControl {
public static void closeTransaction() {
try {
cls.getMethod("closeTransaction").invoke(null);
CLASS.getMethod("closeTransaction").invoke(null);
} catch (Exception e) {
throw new AssertionError(e);
}
@ -38,7 +40,7 @@ public class SurfaceControl {
public static void setDisplayProjection(IBinder displayToken, int orientation, Rect layerStackRect, Rect displayRect) {
try {
cls.getMethod("setDisplayProjection", IBinder.class, int.class, Rect.class, Rect.class)
CLASS.getMethod("setDisplayProjection", IBinder.class, int.class, Rect.class, Rect.class)
.invoke(null, displayToken, orientation, layerStackRect, displayRect);
} catch (Exception e) {
throw new AssertionError(e);
@ -47,7 +49,7 @@ public class SurfaceControl {
public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
try {
cls.getMethod("setDisplayLayerStack", IBinder.class, int.class).invoke(null, displayToken, layerStack);
CLASS.getMethod("setDisplayLayerStack", IBinder.class, int.class).invoke(null, displayToken, layerStack);
} catch (Exception e) {
throw new AssertionError(e);
}
@ -55,7 +57,7 @@ public class SurfaceControl {
public static void setDisplaySurface(IBinder displayToken, Surface surface) {
try {
cls.getMethod("setDisplaySurface", IBinder.class, Surface.class).invoke(null, displayToken, surface);
CLASS.getMethod("setDisplaySurface", IBinder.class, Surface.class).invoke(null, displayToken, surface);
} catch (Exception e) {
throw new AssertionError(e);
}
@ -63,7 +65,7 @@ public class SurfaceControl {
public static IBinder createDisplay(String name, boolean secure) {
try {
return (IBinder) cls.getMethod("createDisplay", String.class, boolean.class).invoke(null, name, secure);
return (IBinder) CLASS.getMethod("createDisplay", String.class, boolean.class).invoke(null, name, secure);
} catch (Exception e) {
throw new AssertionError(e);
}
@ -71,7 +73,7 @@ public class SurfaceControl {
public static void destroyDisplay(IBinder displayToken) {
try {
cls.getMethod("destroyDisplay", IBinder.class).invoke(null, displayToken);
CLASS.getMethod("destroyDisplay", IBinder.class).invoke(null, displayToken);
} catch (Exception e) {
throw new AssertionError(e);
}

View file

@ -3,7 +3,7 @@ package com.genymobile.scrcpy.wrappers;
import android.os.IInterface;
import android.view.IRotationWatcher;
public class WindowManager {
public final class WindowManager {
private final IInterface manager;
public WindowManager(IInterface manager) {