audio: add call redirection audio modes
Add two audio modes corresponding to a call redirection scenario: - AudioManager.MODE_CALL_REDIRECT: PSTN call redirection - AudioManager.MODE_COMMUNICATION_REDIRECT: VoIP call redirection When in call redirect mode, call audio uplink and downlink are not routed to regular audio sinks (e.g. earpiece) or sources (e.g. built in mic) but disconnected. A privileged app can use system APIs to inject and extract call audio and redirect the call to another device. All other media use cases operate as if no call was active. Bug: 189472651 Test: make Change-Id: I3b1a616a72b1f7c97e0e5bf7c9f76c40a28876f1
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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 + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user