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:
Romain Vimont 2023-03-16 22:19:21 +01:00
parent 02f4ff7534
commit 3626d90004

View file

@ -59,61 +59,59 @@ 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.
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
Intent intent = new Intent(Intent.ACTION_MAIN); Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(new ComponentName(FakeContext.PACKAGE_NAME, "com.android.shell.HeapDumpActivity")); intent.setComponent(new ComponentName(FakeContext.PACKAGE_NAME, "com.android.shell.HeapDumpActivity"));
ServiceManager.getActivityManager().startActivityAsUserWithFeature(intent); 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 {
while (attempts-- > 0) { while (attempts-- > 0) {
// 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 { } else {
Ln.d("Failed to start audio capture, retrying..."); Ln.d("Failed to start audio capture, retrying...");
} }
} else {
throw e;
}
} }
} }
} }
private void startRecording() {
recorder = createAudioRecord();
recorder.startRecording();
}
public void start() throws AudioCaptureForegroundException { public void start() throws AudioCaptureForegroundException {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
startWorkaroundAndroid11(); startWorkaroundAndroid11();
try { try {
tryStartRecording(3, 100); tryStartRecording(3, 100);
} finally { } finally {
stopWorkaroundAndroid11(); stopWorkaroundAndroid11();
} }
} else {
startRecording();
}
} }
public void stop() { public void stop() {