diff --git a/core/api/current.txt b/core/api/current.txt index 5656c31c330af..7411d776d15ba 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20732,7 +20732,9 @@ package android.media { field public static final int GET_DEVICES_ALL = 3; // 0x3 field public static final int GET_DEVICES_INPUTS = 1; // 0x1 field public static final int GET_DEVICES_OUTPUTS = 2; // 0x2 + field public static final int MODE_CALL_REDIRECT = 5; // 0x5 field public static final int MODE_CALL_SCREENING = 4; // 0x4 + field public static final int MODE_COMMUNICATION_REDIRECT = 6; // 0x6 field public static final int MODE_CURRENT = -1; // 0xffffffff field public static final int MODE_INVALID = -2; // 0xfffffffe field public static final int MODE_IN_CALL = 2; // 0x2 diff --git a/media/aidl/android/media/audio/common/AudioMode.aidl b/media/aidl/android/media/audio/common/AudioMode.aidl index cc03813776e86..701bcb60bb27d 100644 --- a/media/aidl/android/media/audio/common/AudioMode.aidl +++ b/media/aidl/android/media/audio/common/AudioMode.aidl @@ -45,4 +45,8 @@ enum AudioMode { IN_COMMUNICATION = 3, /** Call screening in progress. */ CALL_SCREEN = 4, + /** PSTN Call redirection in progress. */ + SYS_RESERVED_CALL_REDIRECT = 5, + /** VoIP Call redirection in progress. */ + SYS_RESERVED_COMMUNICATION_REDIRECT = 6, } diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioMode.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioMode.aidl index 8ae1c10fccf58..8256c1c81b77b 100644 --- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioMode.aidl +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioMode.aidl @@ -42,4 +42,6 @@ enum AudioMode { IN_CALL = 2, IN_COMMUNICATION = 3, CALL_SCREEN = 4, + SYS_RESERVED_CALL_REDIRECT = 5, + SYS_RESERVED_COMMUNICATION_REDIRECT = 6, } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index e3ed703f475d5..c6622238a7921 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -30,8 +30,11 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.compat.CompatChanges; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -2839,6 +2842,14 @@ public class AudioManager { } } + /** + * This change id controls use of audio modes for call audio redirection. + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id + /** * Returns the current audio mode. * @@ -2858,6 +2869,12 @@ public class AudioManager { } if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) { mode = MODE_IN_CALL; + } else if (mode == MODE_CALL_REDIRECT + && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) { + mode = MODE_IN_CALL; + } else if (mode == MODE_COMMUNICATION_REDIRECT + && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) { + mode = MODE_IN_COMMUNICATION; } return mode; } catch (RemoteException e) { @@ -3075,13 +3092,26 @@ public class AudioManager { */ public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING; + /** + * A telephony call is established and its audio is being redirected to another device. + */ + public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT; + + /** + * n audio/video chat or VoIP call is established and its audio is being redirected to another + * device. + */ + public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT; + /** @hide */ @IntDef(flag = false, prefix = "MODE_", value = { MODE_NORMAL, MODE_RINGTONE, MODE_IN_CALL, MODE_IN_COMMUNICATION, - MODE_CALL_SCREENING } + MODE_CALL_SCREENING, + MODE_CALL_REDIRECT, + MODE_COMMUNICATION_REDIRECT} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioMode {} diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 60c9e1c308b6c..16cb5f437414b 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -199,7 +199,11 @@ public class AudioSystem /** @hide */ public static final int MODE_CALL_SCREENING = 4; /** @hide */ - public static final int NUM_MODES = 5; + public static final int MODE_CALL_REDIRECT = 5; + /** @hide */ + public static final int MODE_COMMUNICATION_REDIRECT = 6; + /** @hide */ + public static final int NUM_MODES = 7; /** @hide */ public static String modeToString(int mode) { @@ -211,6 +215,8 @@ public class AudioSystem case MODE_NORMAL: return "MODE_NORMAL"; case MODE_RINGTONE: return "MODE_RINGTONE"; case MODE_CALL_SCREENING: return "MODE_CALL_SCREENING"; + case MODE_CALL_REDIRECT: return "MODE_CALL_REDIRECT"; + case MODE_COMMUNICATION_REDIRECT: return "MODE_COMMUNICATION_REDIRECT"; default: return "unknown mode (" + mode + ")"; } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 4dd168252b801..18be9a10a37a7 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4638,12 +4638,13 @@ public class AudioService extends IAudioService.Stub * or recording for VOICE_COMMUNICATION. * or * - It requests a mode different from MODE_IN_COMMUNICATION or MODE_NORMAL + * Note: only privileged apps can request MODE_IN_CALL, MODE_CALL_REDIRECT + * or MODE_COMMUNICATION_REDIRECT. */ public boolean isActive() { return mIsPrivileged || ((mMode == AudioSystem.MODE_IN_COMMUNICATION) && (mRecordingActive || mPlaybackActive)) - || mMode == AudioSystem.MODE_IN_CALL || mMode == AudioSystem.MODE_RINGTONE || mMode == AudioSystem.MODE_CALL_SCREENING; } @@ -4752,9 +4753,13 @@ public class AudioService extends IAudioService.Stub final boolean hasModifyPhoneStatePermission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; - if ((mode == AudioSystem.MODE_IN_CALL) && !hasModifyPhoneStatePermission) { - Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid=" - + pid + ", uid=" + Binder.getCallingUid()); + if ((mode == AudioSystem.MODE_IN_CALL + || mode == AudioSystem.MODE_CALL_REDIRECT + || mode == AudioSystem.MODE_COMMUNICATION_REDIRECT) + && !hasModifyPhoneStatePermission) { + Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(" + + AudioSystem.modeToString(mode) + ") from pid=" + pid + + ", uid=" + Binder.getCallingUid()); return; }