Use separate audio capture code for Android 11
The code to start audio capture is more complicated for Android 11 (launch a fake popup, wait, make several attempts, close the shell package). Use a distinct code path specific to Android 11.
This commit is contained in:
parent
02f4ff7534
commit
3626d90004
1 changed files with 33 additions and 35 deletions
|
@ -59,27 +59,21 @@ public final class AudioCapture {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startWorkaroundAndroid11() {
|
private static void startWorkaroundAndroid11() {
|
||||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
// Android 11 requires Apps to be at foreground to record audio.
|
||||||
// Android 11 requires Apps to be at foreground to record audio.
|
// Normally, each App has its own user ID, so Android checks whether the requesting App has the user ID that's at the foreground.
|
||||||
// Normally, each App has its own user ID, so Android checks whether the requesting App has the user ID that's at the foreground.
|
// But scrcpy server is NOT an App, it's a Java application started from Android shell, so it has the same user ID (2000) with Android
|
||||||
// But scrcpy server is NOT an App, it's a Java application started from Android shell, so it has the same user ID (2000) with Android
|
// shell ("com.android.shell").
|
||||||
// shell ("com.android.shell").
|
// If there is an Activity from Android shell running at foreground, then the permission system will believe scrcpy is also in the
|
||||||
// If there is an Activity from Android shell running at foreground, then the permission system will believe scrcpy is also in the
|
// foreground.
|
||||||
// foreground.
|
Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
Intent intent = new Intent(Intent.ACTION_MAIN);
|
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setComponent(new ComponentName(FakeContext.PACKAGE_NAME, "com.android.shell.HeapDumpActivity"));
|
||||||
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
ServiceManager.getActivityManager().startActivityAsUserWithFeature(intent);
|
||||||
intent.setComponent(new ComponentName(FakeContext.PACKAGE_NAME, "com.android.shell.HeapDumpActivity"));
|
|
||||||
ServiceManager.getActivityManager().startActivityAsUserWithFeature(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void stopWorkaroundAndroid11() {
|
private static void stopWorkaroundAndroid11() {
|
||||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
ServiceManager.getActivityManager().forceStopPackage(FakeContext.PACKAGE_NAME);
|
||||||
ServiceManager.getActivityManager().forceStopPackage(FakeContext.PACKAGE_NAME);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryStartRecording(int attempts, int delayMs) throws AudioCaptureForegroundException {
|
private void tryStartRecording(int attempts, int delayMs) throws AudioCaptureForegroundException {
|
||||||
|
@ -87,32 +81,36 @@ public final class AudioCapture {
|
||||||
// Wait for activity to start
|
// Wait for activity to start
|
||||||
SystemClock.sleep(delayMs);
|
SystemClock.sleep(delayMs);
|
||||||
try {
|
try {
|
||||||
recorder = createAudioRecord();
|
startRecording();
|
||||||
recorder.startRecording();
|
|
||||||
return; // it worked
|
return; // it worked
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
if (attempts == 0) {
|
||||||
if (attempts == 0) {
|
Ln.e("Failed to start audio capture");
|
||||||
Ln.e("Failed to start audio capture");
|
Ln.e("On Android 11, audio capture must be started in the foreground, make sure that the device is unlocked when starting " +
|
||||||
Ln.e("On Android 11, audio capture must be started in the foreground, make sure that the device is unlocked when starting "
|
"scrcpy.");
|
||||||
+ "scrcpy.");
|
throw new AudioCaptureForegroundException();
|
||||||
throw new AudioCaptureForegroundException();
|
|
||||||
} else {
|
|
||||||
Ln.d("Failed to start audio capture, retrying...");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
Ln.d("Failed to start audio capture, retrying...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startRecording() {
|
||||||
|
recorder = createAudioRecord();
|
||||||
|
recorder.startRecording();
|
||||||
|
}
|
||||||
|
|
||||||
public void start() throws AudioCaptureForegroundException {
|
public void start() throws AudioCaptureForegroundException {
|
||||||
startWorkaroundAndroid11();
|
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
||||||
try {
|
startWorkaroundAndroid11();
|
||||||
tryStartRecording(3, 100);
|
try {
|
||||||
} finally {
|
tryStartRecording(3, 100);
|
||||||
stopWorkaroundAndroid11();
|
} finally {
|
||||||
|
stopWorkaroundAndroid11();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startRecording();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue