diff --git a/server/src/main/java/com/genymobile/scrcpy/AndroidVersions.java b/server/src/main/java/com/genymobile/scrcpy/AndroidVersions.java new file mode 100644 index 00000000..8acad7ee --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/AndroidVersions.java @@ -0,0 +1,32 @@ +package com.genymobile.scrcpy; + +import android.os.Build; + +/** + * Android version code constants, done right. + *

+ * API levels + */ +public final class AndroidVersions { + + private AndroidVersions() { + // not instantiable + } + + public static final int API_20_ANDROID_4_4 = Build.VERSION_CODES.KITKAT_WATCH; + public static final int API_21_ANDROID_5_0 = Build.VERSION_CODES.LOLLIPOP; + public static final int API_22_ANDROID_5_1 = Build.VERSION_CODES.LOLLIPOP_MR1; + public static final int API_23_ANDROID_6_0 = Build.VERSION_CODES.M; + public static final int API_24_ANDROID_7_0 = Build.VERSION_CODES.N; + public static final int API_25_ANDROID_7_1 = Build.VERSION_CODES.N_MR1; + public static final int API_26_ANDROID_8_0 = Build.VERSION_CODES.O; + public static final int API_27_ANDROID_8_1 = Build.VERSION_CODES.O_MR1; + public static final int API_28_ANDROID_9 = Build.VERSION_CODES.P; + public static final int API_29_ANDROID_10 = Build.VERSION_CODES.Q; + public static final int API_30_ANDROID_11 = Build.VERSION_CODES.R; + public static final int API_31_ANDROID_12 = Build.VERSION_CODES.S; + public static final int API_32_ANDROID_12L = Build.VERSION_CODES.S_V2; + public static final int API_33_ANDROID_13 = Build.VERSION_CODES.TIRAMISU; + public static final int API_34_ANDROID_14 = Build.VERSION_CODES.UPSIDE_DOWN_CAKE; + +} diff --git a/server/src/main/java/com/genymobile/scrcpy/FakeContext.java b/server/src/main/java/com/genymobile/scrcpy/FakeContext.java index 2ea7bf4a..0b086cc5 100644 --- a/server/src/main/java/com/genymobile/scrcpy/FakeContext.java +++ b/server/src/main/java/com/genymobile/scrcpy/FakeContext.java @@ -4,7 +4,6 @@ import android.annotation.TargetApi; import android.content.AttributionSource; import android.content.Context; import android.content.ContextWrapper; -import android.os.Build; import android.os.Process; public final class FakeContext extends ContextWrapper { @@ -32,7 +31,7 @@ public final class FakeContext extends ContextWrapper { return PACKAGE_NAME; } - @TargetApi(Build.VERSION_CODES.S) + @TargetApi(AndroidVersions.API_31_ANDROID_12) @Override public AttributionSource getAttributionSource() { AttributionSource.Builder builder = new AttributionSource.Builder(Process.SHELL_UID); diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 7817fdf5..555cf97a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -121,7 +121,7 @@ public final class Server { } private static void scrcpy(Options options) throws IOException, ConfigurationException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && options.getVideoSource() == VideoSource.CAMERA) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_31_ANDROID_12 && options.getVideoSource() == VideoSource.CAMERA) { Ln.e("Camera mirroring is not supported before Android 12"); throw new ConfigurationException("Camera mirroring is not supported"); } diff --git a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java index 7de98b72..eec00a04 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java +++ b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java @@ -52,7 +52,7 @@ public final class Workarounds { } public static void apply() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_31_ANDROID_12) { // On some Samsung devices, DisplayManagerGlobal.getDisplayInfoLocked() calls ActivityThread.currentActivityThread().getConfiguration(), // which requires a non-null ConfigurationController. // ConfigurationController was introduced in Android 12, so do not attempt to set it on lower versions. @@ -155,7 +155,7 @@ public final class Workarounds { } } - @TargetApi(Build.VERSION_CODES.R) + @TargetApi(AndroidVersions.API_30_ANDROID_11) @SuppressLint("WrongConstant,MissingPermission") public static AudioRecord createAudioRecord(int source, int sampleRate, int channelConfig, int channels, int channelMask, int encoding) throws AudioCaptureException { @@ -226,7 +226,7 @@ public final class Workarounds { int[] session = new int[]{AudioManager.AUDIO_SESSION_ID_GENERATE}; int initResult; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_31_ANDROID_12) { // private native final int native_setup(Object audiorecord_this, // Object /*AudioAttributes*/ attributes, // int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, @@ -252,7 +252,7 @@ public final class Workarounds { Method getParcelMethod = attributionSourceState.getClass().getDeclaredMethod("getParcel"); Parcel attributionSourceParcel = (Parcel) getParcelMethod.invoke(attributionSourceState); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_34_ANDROID_14) { // private native int native_setup(Object audiorecordThis, // Object /*AudioAttributes*/ attributes, // int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, diff --git a/server/src/main/java/com/genymobile/scrcpy/audio/AudioDirectCapture.java b/server/src/main/java/com/genymobile/scrcpy/audio/AudioDirectCapture.java index 8d4a4c2d..5c859738 100644 --- a/server/src/main/java/com/genymobile/scrcpy/audio/AudioDirectCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/audio/AudioDirectCapture.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.audio; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.FakeContext; import com.genymobile.scrcpy.Workarounds; import com.genymobile.scrcpy.util.Ln; @@ -45,11 +46,11 @@ public class AudioDirectCapture implements AudioCapture { } } - @TargetApi(Build.VERSION_CODES.M) + @TargetApi(AndroidVersions.API_23_ANDROID_6_0) @SuppressLint({"WrongConstant", "MissingPermission"}) private static AudioRecord createAudioRecord(int audioSource) { AudioRecord.Builder builder = new AudioRecord.Builder(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_31_ANDROID_12) { // On older APIs, Workarounds.fillAppInfo() must be called beforehand builder.setContext(FakeContext.get()); } @@ -117,7 +118,7 @@ public class AudioDirectCapture implements AudioCapture { @Override public void checkCompatibility() throws AudioCaptureException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_30_ANDROID_11) { Ln.w("Audio disabled: it is not supported before Android 11"); throw new AudioCaptureException(); } @@ -125,7 +126,7 @@ public class AudioDirectCapture implements AudioCapture { @Override public void start() throws AudioCaptureException { - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { + if (Build.VERSION.SDK_INT == AndroidVersions.API_30_ANDROID_11) { startWorkaroundAndroid11(); try { tryStartRecording(5, 100); @@ -146,7 +147,7 @@ public class AudioDirectCapture implements AudioCapture { } @Override - @TargetApi(Build.VERSION_CODES.N) + @TargetApi(AndroidVersions.API_24_ANDROID_7_0) public int read(ByteBuffer outDirectBuffer, MediaCodec.BufferInfo outBufferInfo) { return reader.read(outDirectBuffer, outBufferInfo); } diff --git a/server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java b/server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java index f462431a..fcc0c52f 100644 --- a/server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.audio; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.AsyncProcessor; import com.genymobile.scrcpy.device.ConfigurationException; import com.genymobile.scrcpy.device.Streamer; @@ -93,7 +94,7 @@ public final class AudioEncoder implements AsyncProcessor { return format; } - @TargetApi(Build.VERSION_CODES.N) + @TargetApi(AndroidVersions.API_24_ANDROID_7_0) private void inputThread(MediaCodec mediaCodec, AudioCapture capture) throws IOException, InterruptedException { final MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); @@ -175,9 +176,9 @@ public final class AudioEncoder implements AsyncProcessor { } } - @TargetApi(Build.VERSION_CODES.M) + @TargetApi(AndroidVersions.API_23_ANDROID_6_0) private void encode() throws IOException, ConfigurationException, AudioCaptureException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_30_ANDROID_11) { Ln.w("Audio disabled: it is not supported before Android 11"); streamer.writeDisableStream(false); return; @@ -314,7 +315,7 @@ public final class AudioEncoder implements AsyncProcessor { } private final class EncoderCallback extends MediaCodec.Callback { - @TargetApi(Build.VERSION_CODES.N) + @TargetApi(AndroidVersions.API_24_ANDROID_7_0) @Override public void onInputBufferAvailable(MediaCodec codec, int index) { try { diff --git a/server/src/main/java/com/genymobile/scrcpy/audio/AudioPlaybackCapture.java b/server/src/main/java/com/genymobile/scrcpy/audio/AudioPlaybackCapture.java index e38493f2..009a239a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/audio/AudioPlaybackCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/audio/AudioPlaybackCapture.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.audio; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.FakeContext; import com.genymobile.scrcpy.util.Ln; @@ -108,7 +109,7 @@ public final class AudioPlaybackCapture implements AudioCapture { @Override public void checkCompatibility() throws AudioCaptureException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_33_ANDROID_13) { Ln.w("Audio disabled: audio playback capture source not supported before Android 13"); throw new AudioCaptureException(); } @@ -130,7 +131,7 @@ public final class AudioPlaybackCapture implements AudioCapture { } @Override - @TargetApi(Build.VERSION_CODES.N) + @TargetApi(AndroidVersions.API_24_ANDROID_7_0) public int read(ByteBuffer outDirectBuffer, MediaCodec.BufferInfo outBufferInfo) { return reader.read(outDirectBuffer, outBufferInfo); } diff --git a/server/src/main/java/com/genymobile/scrcpy/audio/AudioRawRecorder.java b/server/src/main/java/com/genymobile/scrcpy/audio/AudioRawRecorder.java index 3924c205..9645bbbd 100644 --- a/server/src/main/java/com/genymobile/scrcpy/audio/AudioRawRecorder.java +++ b/server/src/main/java/com/genymobile/scrcpy/audio/AudioRawRecorder.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.audio; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.AsyncProcessor; import com.genymobile.scrcpy.device.Streamer; import com.genymobile.scrcpy.util.IO; @@ -24,7 +25,7 @@ public final class AudioRawRecorder implements AsyncProcessor { } private void record() throws IOException, AudioCaptureException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_30_ANDROID_11) { Ln.w("Audio disabled: it is not supported before Android 11"); streamer.writeDisableStream(false); return; diff --git a/server/src/main/java/com/genymobile/scrcpy/audio/AudioRecordReader.java b/server/src/main/java/com/genymobile/scrcpy/audio/AudioRecordReader.java index 80286831..32b42257 100644 --- a/server/src/main/java/com/genymobile/scrcpy/audio/AudioRecordReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/audio/AudioRecordReader.java @@ -1,12 +1,12 @@ package com.genymobile.scrcpy.audio; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.util.Ln; import android.annotation.TargetApi; import android.media.AudioRecord; import android.media.AudioTimestamp; import android.media.MediaCodec; -import android.os.Build; import java.nio.ByteBuffer; @@ -26,7 +26,7 @@ public class AudioRecordReader { this.recorder = recorder; } - @TargetApi(Build.VERSION_CODES.N) + @TargetApi(AndroidVersions.API_24_ANDROID_7_0) public int read(ByteBuffer outDirectBuffer, MediaCodec.BufferInfo outBufferInfo) { int r = recorder.read(outDirectBuffer, AudioConfig.MAX_READ_SIZE); if (r <= 0) { diff --git a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java index b445427d..8fa27e81 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.control; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.AsyncProcessor; import com.genymobile.scrcpy.CleanUp; import com.genymobile.scrcpy.device.Device; @@ -318,7 +319,7 @@ public class Controller implements AsyncProcessor { * * Otherwise, Chrome does not work properly: */ - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && source == InputDevice.SOURCE_MOUSE) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_23_ANDROID_6_0 && source == InputDevice.SOURCE_MOUSE) { if (action == MotionEvent.ACTION_DOWN) { if (actionButton == buttons) { // First button pressed: ACTION_DOWN @@ -423,7 +424,7 @@ public class Controller implements AsyncProcessor { private void getClipboard(int copyKey) { // On Android >= 7, press the COPY or CUT key if requested - if (copyKey != ControlMessage.COPY_KEY_NONE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) { + if (copyKey != ControlMessage.COPY_KEY_NONE && Build.VERSION.SDK_INT >= AndroidVersions.API_24_ANDROID_7_0 && device.supportsInputEvents()) { int key = copyKey == ControlMessage.COPY_KEY_COPY ? KeyEvent.KEYCODE_COPY : KeyEvent.KEYCODE_CUT; // Wait until the event is finished, to ensure that the clipboard text we read just after is the correct one device.pressReleaseKeycode(key, Device.INJECT_MODE_WAIT_FOR_FINISH); @@ -448,7 +449,7 @@ public class Controller implements AsyncProcessor { } // On Android >= 7, also press the PASTE key if requested - if (paste && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) { + if (paste && Build.VERSION.SDK_INT >= AndroidVersions.API_24_ANDROID_7_0 && device.supportsInputEvents()) { device.pressReleaseKeycode(KeyEvent.KEYCODE_PASTE, Device.INJECT_MODE_ASYNC); } diff --git a/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java b/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java index d8cfd81f..8121adfc 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.control; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.util.Ln; import com.genymobile.scrcpy.util.StringUtils; @@ -38,7 +39,7 @@ public final class UhidManager { public UhidManager(DeviceMessageSender sender) { this.sender = sender; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_23_ANDROID_6_0) { HandlerThread thread = new HandlerThread("UHidManager"); thread.start(); queue = thread.getLooper().getQueue(); @@ -71,7 +72,7 @@ public final class UhidManager { } private void registerUhidListener(int id, FileDescriptor fd) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_23_ANDROID_6_0) { queue.addOnFileDescriptorEventListener(fd, MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT, (fd2, events) -> { try { buffer.clear(); @@ -97,7 +98,7 @@ public final class UhidManager { } private void unregisterUhidListener(FileDescriptor fd) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_23_ANDROID_6_0) { queue.removeOnFileDescriptorEventListener(fd); } } diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Device.java b/server/src/main/java/com/genymobile/scrcpy/device/Device.java index 5a1083fd..1f375942 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Device.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.device; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.Options; import com.genymobile.scrcpy.util.Ln; import com.genymobile.scrcpy.util.LogUtils; @@ -104,7 +105,7 @@ public final class Device { } }, displayId); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_29_ANDROID_10) { ServiceManager.getWindowManager().registerDisplayFoldListener(new IDisplayFoldListener.Stub() { @Override public void onDisplayFoldChanged(int displayId, boolean folded) { @@ -161,8 +162,8 @@ public final class Device { Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted"); } - // main display or any display on Android >= Q - supportsInputEvents = displayId == 0 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + // main display or any display on Android >= 10 + supportsInputEvents = displayId == 0 || Build.VERSION.SDK_INT >= AndroidVersions.API_29_ANDROID_10; if (!supportsInputEvents) { Ln.w("Input events are not supported for secondary displays before Android 10"); } @@ -215,7 +216,7 @@ public final class Device { } public static boolean supportsInputEvents(int displayId) { - return displayId == 0 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + return displayId == 0 || Build.VERSION.SDK_INT >= AndroidVersions.API_29_ANDROID_10; } public boolean supportsInputEvents() { @@ -323,10 +324,10 @@ public final class Device { * @param mode one of the {@code POWER_MODE_*} constants */ public static boolean setScreenPowerMode(int mode) { - boolean applyToMultiPhysicalDisplays = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + boolean applyToMultiPhysicalDisplays = Build.VERSION.SDK_INT >= AndroidVersions.API_29_ANDROID_10; if (applyToMultiPhysicalDisplays - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE + && Build.VERSION.SDK_INT >= AndroidVersions.API_34_ANDROID_14 && Build.BRAND.equalsIgnoreCase("honor") && SurfaceControl.hasGetBuildInDisplayMethod()) { // Workaround for Honor devices with Android 14: @@ -338,7 +339,7 @@ public final class Device { if (applyToMultiPhysicalDisplays) { // On Android 14, these internal methods have been moved to DisplayControl boolean useDisplayControl = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && !SurfaceControl.hasGetPhysicalDisplayIdsMethod(); + Build.VERSION.SDK_INT >= AndroidVersions.API_34_ANDROID_14 && !SurfaceControl.hasGetPhysicalDisplayIdsMethod(); // Change the power mode for all physical displays long[] physicalDisplayIds = useDisplayControl ? DisplayControl.getPhysicalDisplayIds() : SurfaceControl.getPhysicalDisplayIds(); diff --git a/server/src/main/java/com/genymobile/scrcpy/util/IO.java b/server/src/main/java/com/genymobile/scrcpy/util/IO.java index d9247a98..b953f290 100644 --- a/server/src/main/java/com/genymobile/scrcpy/util/IO.java +++ b/server/src/main/java/com/genymobile/scrcpy/util/IO.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.util; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.BuildConfig; import android.os.Build; @@ -31,7 +32,7 @@ public final class IO { } public static void writeFully(FileDescriptor fd, ByteBuffer from) throws IOException { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_23_ANDROID_6_0) { while (from.hasRemaining()) { write(fd, from); } diff --git a/server/src/main/java/com/genymobile/scrcpy/util/Settings.java b/server/src/main/java/com/genymobile/scrcpy/util/Settings.java index d9e82d62..e6465525 100644 --- a/server/src/main/java/com/genymobile/scrcpy/util/Settings.java +++ b/server/src/main/java/com/genymobile/scrcpy/util/Settings.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.util; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.wrappers.ContentProvider; import com.genymobile.scrcpy.wrappers.ServiceManager; @@ -34,7 +35,7 @@ public final class Settings { } public static String getValue(String table, String key) throws SettingsException { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { + if (Build.VERSION.SDK_INT <= AndroidVersions.API_30_ANDROID_11) { // on Android >= 12, it always fails: try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) { return provider.getValue(table, key); @@ -47,7 +48,7 @@ public final class Settings { } 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 <= AndroidVersions.API_30_ANDROID_11) { // on Android >= 12, it always fails: try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) { provider.putValue(table, key, value); @@ -60,7 +61,7 @@ public final class Settings { } 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 <= AndroidVersions.API_30_ANDROID_11) { // on Android >= 12, it always fails: try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) { String oldValue = provider.getValue(table, key); diff --git a/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java index 3b8fc59b..a5fa4b06 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.video; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.device.Size; import com.genymobile.scrcpy.util.HandlerExecutor; import com.genymobile.scrcpy.util.Ln; @@ -20,7 +21,6 @@ import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.MediaCodec; -import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.util.Range; @@ -118,7 +118,7 @@ public class CameraCapture extends SurfaceCapture { return null; } - @TargetApi(Build.VERSION_CODES.N) + @TargetApi(AndroidVersions.API_24_ANDROID_7_0) private static Size selectSize(String cameraId, Size explicitSize, int maxSize, CameraAspectRatio aspectRatio, boolean highSpeed) throws CameraAccessException { if (explicitSize != null) { @@ -242,7 +242,7 @@ public class CameraCapture extends SurfaceCapture { } @SuppressLint("MissingPermission") - @TargetApi(Build.VERSION_CODES.S) + @TargetApi(AndroidVersions.API_31_ANDROID_12) private CameraDevice openCamera(String id) throws CameraAccessException, InterruptedException { CompletableFuture future = new CompletableFuture<>(); ServiceManager.getCameraManager().openCamera(id, new CameraDevice.StateCallback() { @@ -289,7 +289,7 @@ public class CameraCapture extends SurfaceCapture { } } - @TargetApi(Build.VERSION_CODES.S) + @TargetApi(AndroidVersions.API_31_ANDROID_12) private CameraCaptureSession createCaptureSession(CameraDevice camera, Surface surface) throws CameraAccessException, InterruptedException { CompletableFuture future = new CompletableFuture<>(); OutputConfiguration outputConfig = new OutputConfiguration(surface); @@ -328,7 +328,7 @@ public class CameraCapture extends SurfaceCapture { return requestBuilder.build(); } - @TargetApi(Build.VERSION_CODES.S) + @TargetApi(AndroidVersions.API_31_ANDROID_12) private void setRepeatingRequest(CameraCaptureSession session, CaptureRequest request) throws CameraAccessException, InterruptedException { CameraCaptureSession.CaptureCallback callback = new CameraCaptureSession.CaptureCallback() { @Override diff --git a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java index 62afb263..e6357410 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.video; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.device.Device; import com.genymobile.scrcpy.device.Size; import com.genymobile.scrcpy.util.Ln; @@ -103,8 +104,8 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList private static IBinder createDisplay() throws Exception { // Since Android 12 (preview), secure displays could not be created with shell permissions anymore. // On Android 12 preview, SDK_INT is still R (not S), but CODENAME is "S". - boolean secure = Build.VERSION.SDK_INT < Build.VERSION_CODES.R || (Build.VERSION.SDK_INT == Build.VERSION_CODES.R && !"S".equals( - Build.VERSION.CODENAME)); + boolean secure = Build.VERSION.SDK_INT < AndroidVersions.API_30_ANDROID_11 || (Build.VERSION.SDK_INT == AndroidVersions.API_30_ANDROID_11 + && !"S".equals(Build.VERSION.CODENAME)); return SurfaceControl.createDisplay("scrcpy", secure); } diff --git a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java index 41c38642..5a9417da 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.video; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.AsyncProcessor; import com.genymobile.scrcpy.device.ConfigurationException; import com.genymobile.scrcpy.device.Size; @@ -238,7 +239,7 @@ public class SurfaceEncoder implements AsyncProcessor { // must be present to configure the encoder, but does not impact the actual frame rate, which is variable format.setInteger(MediaFormat.KEY_FRAME_RATE, 60); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_24_ANDROID_7_0) { format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED); } format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL); diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ActivityManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ActivityManager.java index bb1ca0d4..c907e12f 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ActivityManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ActivityManager.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.wrappers; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.FakeContext; import com.genymobile.scrcpy.util.Ln; @@ -7,7 +8,6 @@ import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Intent; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.IInterface; @@ -63,7 +63,7 @@ public final class ActivityManager { return removeContentProviderExternalMethod; } - @TargetApi(Build.VERSION_CODES.Q) + @TargetApi(AndroidVersions.API_29_ANDROID_10) private ContentProvider getContentProviderExternal(String name, IBinder token) { try { Method method = getGetContentProviderExternalMethod(); 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 c5f007fe..791df0f8 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.wrappers; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.FakeContext; import com.genymobile.scrcpy.util.Ln; @@ -36,7 +37,7 @@ public final class ClipboardManager { private Method getGetPrimaryClipMethod() throws NoSuchMethodException { if (getPrimaryClipMethod == null) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class); return getPrimaryClipMethod; } @@ -99,7 +100,7 @@ public final class ClipboardManager { private Method getSetPrimaryClipMethod() throws NoSuchMethodException { if (setPrimaryClipMethod == null) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class); return setPrimaryClipMethod; } @@ -137,7 +138,7 @@ public final class ClipboardManager { } private static ClipData getPrimaryClip(Method method, int methodVersion, IInterface manager) throws ReflectiveOperationException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME); } @@ -161,7 +162,7 @@ public final class ClipboardManager { } private static void setPrimaryClip(Method method, int methodVersion, IInterface manager, ClipData clipData) throws ReflectiveOperationException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { method.invoke(manager, clipData, FakeContext.PACKAGE_NAME); return; } @@ -210,7 +211,7 @@ public final class ClipboardManager { private static void addPrimaryClipChangedListener(Method method, int methodVersion, IInterface manager, IOnPrimaryClipChangedListener listener) throws ReflectiveOperationException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { method.invoke(manager, listener, FakeContext.PACKAGE_NAME); return; } @@ -230,7 +231,7 @@ public final class ClipboardManager { private Method getAddPrimaryClipChangedListener() throws NoSuchMethodException { if (addPrimaryClipChangedListener == null) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { addPrimaryClipChangedListener = manager.getClass() .getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class); } else { diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ContentProvider.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ContentProvider.java index 7e92ac50..f625b398 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ContentProvider.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ContentProvider.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.wrappers; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.FakeContext; import com.genymobile.scrcpy.util.Ln; import com.genymobile.scrcpy.util.SettingsException; @@ -51,7 +52,7 @@ public final class ContentProvider implements Closeable { @SuppressLint("PrivateApi") private Method getCallMethod() throws NoSuchMethodException { if (callMethod == null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_31_ANDROID_12) { callMethod = provider.getClass().getMethod("call", AttributionSource.class, String.class, String.class, String.class, Bundle.class); callMethodVersion = 0; } else { @@ -79,7 +80,7 @@ public final class ContentProvider implements Closeable { Method method = getCallMethod(); Object[] args; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && callMethodVersion == 0) { + if (Build.VERSION.SDK_INT >= AndroidVersions.API_31_ANDROID_12 && callMethodVersion == 0) { args = new Object[]{FakeContext.get().getAttributionSource(), "settings", callMethod, arg, extras}; } else { switch (callMethodVersion) { diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayControl.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayControl.java index cc9d5526..a57f7948 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayControl.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayControl.java @@ -1,16 +1,16 @@ package com.genymobile.scrcpy.wrappers; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.util.Ln; import android.annotation.SuppressLint; import android.annotation.TargetApi; -import android.os.Build; import android.os.IBinder; import java.lang.reflect.Method; @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi", "BlockedPrivateApi"}) -@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +@TargetApi(AndroidVersions.API_34_ANDROID_14) public final class DisplayControl { private static final Class CLASS; diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java index 0a56f347..615ceb42 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.wrappers; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.util.Ln; import android.annotation.SuppressLint; @@ -24,7 +25,7 @@ public final class PowerManager { private Method getIsScreenOnMethod() throws NoSuchMethodException { if (isScreenOnMethod == null) { @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 >= AndroidVersions.API_20_ANDROID_4_4 ? "isInteractive" : "isScreenOn"; isScreenOnMethod = manager.getClass().getMethod(methodName); } return isScreenOnMethod; diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java index 038e7ca0..3bae4a37 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java @@ -1,5 +1,6 @@ package com.genymobile.scrcpy.wrappers; +import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.util.Ln; import android.annotation.SuppressLint; @@ -83,9 +84,9 @@ public final class SurfaceControl { private static Method getGetBuiltInDisplayMethod() throws NoSuchMethodException { if (getBuiltInDisplayMethod == null) { - // the method signature has changed in Android Q + // the method signature has changed in Android 10 // - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { getBuiltInDisplayMethod = CLASS.getMethod("getBuiltInDisplay", int.class); } else { getBuiltInDisplayMethod = CLASS.getMethod("getInternalDisplayToken"); @@ -106,7 +107,7 @@ public final class SurfaceControl { public static IBinder getBuiltInDisplay() { try { Method method = getGetBuiltInDisplayMethod(); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < AndroidVersions.API_29_ANDROID_10) { // call getBuiltInDisplay(0) return (IBinder) method.invoke(null, 0); }