Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
9f9b852ae7 | |||
8bf276486f |
@ -2,11 +2,11 @@ package com.genymobile.scrcpy;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.AttributionSource;
|
import android.content.AttributionSource;
|
||||||
import android.content.ContextWrapper;
|
import android.content.MutableContextWrapper;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
|
||||||
public final class FakeContext extends ContextWrapper {
|
public final class FakeContext extends MutableContextWrapper {
|
||||||
|
|
||||||
public static final String PACKAGE_NAME = "com.android.shell";
|
public static final String PACKAGE_NAME = "com.android.shell";
|
||||||
public static final int ROOT_UID = 0; // Like android.os.Process.ROOT_UID, but before API 29
|
public static final int ROOT_UID = 0; // Like android.os.Process.ROOT_UID, but before API 29
|
||||||
|
@ -99,26 +99,7 @@ public final class Server {
|
|||||||
boolean audio = options.getAudio();
|
boolean audio = options.getAudio();
|
||||||
boolean sendDummyByte = options.getSendDummyByte();
|
boolean sendDummyByte = options.getSendDummyByte();
|
||||||
|
|
||||||
Workarounds.prepareMainLooper();
|
Workarounds.apply(audio);
|
||||||
|
|
||||||
// Workarounds must be applied for Meizu phones:
|
|
||||||
// - <https://github.com/Genymobile/scrcpy/issues/240>
|
|
||||||
// - <https://github.com/Genymobile/scrcpy/issues/365>
|
|
||||||
// - <https://github.com/Genymobile/scrcpy/issues/2656>
|
|
||||||
//
|
|
||||||
// But only apply when strictly necessary, since workarounds can cause other issues:
|
|
||||||
// - <https://github.com/Genymobile/scrcpy/issues/940>
|
|
||||||
// - <https://github.com/Genymobile/scrcpy/issues/994>
|
|
||||||
if (Build.BRAND.equalsIgnoreCase("meizu")) {
|
|
||||||
Workarounds.fillAppInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before Android 11, audio is not supported.
|
|
||||||
// Since Android 12, we can properly set a context on the AudioRecord.
|
|
||||||
// Only on Android 11 we must fill the application context for the AudioRecord to work.
|
|
||||||
if (audio && Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
|
||||||
Workarounds.fillAppContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<AsyncProcessor> asyncProcessors = new ArrayList<>();
|
List<AsyncProcessor> asyncProcessors = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
|||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.AttributionSource;
|
import android.content.AttributionSource;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
@ -27,8 +28,55 @@ public final class Workarounds {
|
|||||||
// not instantiable
|
// not instantiable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void apply(boolean audio) {
|
||||||
|
Workarounds.prepareMainLooper();
|
||||||
|
|
||||||
|
boolean mustFillAppInfo = false;
|
||||||
|
boolean mustFillBaseContext = false;
|
||||||
|
boolean mustFillAppContext = false;
|
||||||
|
|
||||||
|
|
||||||
|
if (Build.BRAND.equalsIgnoreCase("meizu")) {
|
||||||
|
// Workarounds must be applied for Meizu phones:
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/240>
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/365>
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/2656>
|
||||||
|
//
|
||||||
|
// But only apply when strictly necessary, since workarounds can cause other issues:
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/940>
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/994>
|
||||||
|
mustFillAppInfo = true;
|
||||||
|
} else if (Build.BRAND.equalsIgnoreCase("honor")) {
|
||||||
|
// Honor devices require in addition a system context as a base context of FakeContext:
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/4015>
|
||||||
|
// The system context must not be set for all devices, because it would cause other problems:
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/4015#issuecomment-1595382142>
|
||||||
|
// - <https://github.com/Genymobile/scrcpy/issues/3805#issuecomment-1596148031>
|
||||||
|
mustFillAppInfo = true;
|
||||||
|
mustFillBaseContext = true;
|
||||||
|
mustFillAppContext = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio && Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
||||||
|
// Before Android 11, audio is not supported.
|
||||||
|
// Since Android 12, we can properly set a context on the AudioRecord.
|
||||||
|
// Only on Android 11 we must fill the application context for the AudioRecord to work.
|
||||||
|
mustFillAppContext = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mustFillAppInfo) {
|
||||||
|
Workarounds.fillAppInfo();
|
||||||
|
}
|
||||||
|
if (mustFillBaseContext) {
|
||||||
|
Workarounds.fillBaseContext();
|
||||||
|
}
|
||||||
|
if (mustFillAppContext) {
|
||||||
|
Workarounds.fillAppContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static void prepareMainLooper() {
|
private static void prepareMainLooper() {
|
||||||
// Some devices internally create a Handler when creating an input Surface, causing an exception:
|
// Some devices internally create a Handler when creating an input Surface, causing an exception:
|
||||||
// "Can't create handler inside thread that has not called Looper.prepare()"
|
// "Can't create handler inside thread that has not called Looper.prepare()"
|
||||||
// <https://github.com/Genymobile/scrcpy/issues/240>
|
// <https://github.com/Genymobile/scrcpy/issues/240>
|
||||||
@ -57,7 +105,7 @@ public final class Workarounds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
|
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
|
||||||
public static void fillAppInfo() {
|
private static void fillAppInfo() {
|
||||||
try {
|
try {
|
||||||
fillActivityThread();
|
fillActivityThread();
|
||||||
|
|
||||||
@ -86,7 +134,7 @@ public final class Workarounds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
|
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
|
||||||
public static void fillAppContext() {
|
private static void fillAppContext() {
|
||||||
try {
|
try {
|
||||||
fillActivityThread();
|
fillActivityThread();
|
||||||
|
|
||||||
@ -105,6 +153,19 @@ public final class Workarounds {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void fillBaseContext() {
|
||||||
|
try {
|
||||||
|
fillActivityThread();
|
||||||
|
|
||||||
|
Method getSystemContextMethod = activityThreadClass.getDeclaredMethod("getSystemContext");
|
||||||
|
Context context = (Context) getSystemContextMethod.invoke(activityThread);
|
||||||
|
FakeContext.get().setBaseContext(context);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
// this is a workaround, so failing is not an error
|
||||||
|
Ln.d("Could not fill base context: " + throwable.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.R)
|
@TargetApi(Build.VERSION_CODES.R)
|
||||||
@SuppressLint("WrongConstant,MissingPermission,BlockedPrivateApi,SoonBlockedPrivateApi,DiscouragedPrivateApi")
|
@SuppressLint("WrongConstant,MissingPermission,BlockedPrivateApi,SoonBlockedPrivateApi,DiscouragedPrivateApi")
|
||||||
public static AudioRecord createAudioRecord(int source, int sampleRate, int channelConfig, int channels, int channelMask, int encoding) {
|
public static AudioRecord createAudioRecord(int source, int sampleRate, int channelConfig, int channels, int channelMask, int encoding) {
|
||||||
|
Reference in New Issue
Block a user