Android - 如何为 phone 通话打开扬声器phone 和最大音量

Android - How to turn on speakerphone and max volume for phone call

我以为我可以在 PhoneStateListener 内打开扬声器并将音量设置为最大,但我在测试时无法正常工作。我正在使用 AudioManager 尝试打开扬声器并设置音量。这不是正确的方法吗?为什么以下代码无法启用扬声器?

class PlaceCall : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        telephonyManager.listen(CallListener(this), PhoneStateListener.LISTEN_CALL_STATE)
        val callIntent = Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneNumber))
        startActivity(callIntent)
        ...
    }
}
class CallListener(cont: Context) : PhoneStateListener() {
    private var context: Context = cont

    override fun onCallStateChanged(state: Int, phoneNumber: String?) {
        val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0) //I believe this should set call volume to max?
        audioManager.isSpeakerphoneOn = true //I believe this should enable speakerphone, but it doesn't during my tests
    }
}
AndroidManifest.xml
...
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
...

编辑: 我也尝试添加一个 BroadcastReceiver 但它并没有改变结果。扬声器仍未启用。这没有意义,我不知道我做错了什么。下面是添加了新 BroadcastReciever 的更新代码(上面的代码仍然相同)。

AndroidManifest.xml (updated)
...
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application>
    <receiver android:name=".ServiceReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </receiver>
</application>
...
class ServiceReceiver : BroadcastReceiver() {
    lateinit var telephonyManager: TelephonyManager

    override fun onReceive(context: Context, intent: Intent) {
        telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        telephonyManager.listen(CallListener(context), PhoneStateListener.LISTEN_CALL_STATE)
        val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        audioManager.mode = AudioManager.MODE_IN_CALL
        audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0)
        audioManager.isSpeakerphoneOn = true
    }
}

a PhoneStateListener 顾名思义只是一个监听器,它不能对当前调用执行操作,这是默认 Phone 应用程序的职责。

好消息是您可以让用户将您的应用设置为默认 Phone 应用,但它会强制您实施某些可能超出您的应用范围的活动和服务。

您需要实现自己的拨号盘 activity 来拨打电话,您自己的 InCallService 来处理活动呼叫,以及您自己的 in-call UI 来允许用户静音、打开扬声器、连接蓝牙、在 call-waiting 上拨打电话、在通话中发送拨号音等

您可以查看 this series of medium posts 如何将您的应用设为默认 Phone 应用。

将您的应用设置为默认 phone 应用,并且您的应用控制当前应用后,您可以使用 setAudioRoute 打开扬声器 phone。

编辑:

您可以尝试在 AudioManager 中使用 setSpeakerphoneOnisX 始终用于检查值,setX 用于修改值),但是文档说:

This method should only be used by applications that replace the platform-wide management of audio settings or the main telephony application.

我不确定 Android 是否通过阻止应用程序调用此方法来强制执行此操作,如果是,则在哪个 Android 平台上执行此操作,但您可以尝试一下。

还有一种方法是使用 java 反射来访问隐藏的 API、see here,但是使用反射几乎肯定会在最近版本的 Android 上崩溃,并且可能会阻止您的应用进入 Google Play。即便如此,还是值得一试。