如何在Android L中以编程方式打开来电扬声器?

21

我希望在我的安卓5.0手机上使用电话的GUI(电话GUI)接听来电。我找到了一种方法,需要创建一个活动以发送某些操作来打开电话GUI。我已成功打开了来电的电话GUI。问题是如何打开电话GUI的扬声器。我尝试了代码但它没有打开。你能帮我解决这个问题吗?

audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.setMode(AudioManager.MODE_IN_CALL);
if (!audioManager.isSpeakerphoneOn())
     audioManager.setSpeakerphoneOn(true);
audioManager.setMode(AudioManager.MODE_NORMAL);

清单

<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
此外,我们是否有更简洁的方法来接受来电并使用应答电话的意图进行打开。我的方法很长,因为它使用了一个Activity。
这是我的完整类代码。
public class AcceptCallActivity extends Activity {

    private static final String MANUFACTURER_HTC = "HTC";
    private KeyguardManager keyguardManager;
    private AudioManager audioManager;
    private CallStateReceiver callStateReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);        
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerCallStateReceiver();
        updateWindowFlags();
        acceptCall();
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (callStateReceiver != null) {
            unregisterReceiver(callStateReceiver);
            callStateReceiver = null;
        }
    }

    private void registerCallStateReceiver() {
        callStateReceiver = new CallStateReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
        registerReceiver(callStateReceiver, intentFilter);
    }

    private void updateWindowFlags() {
        if (keyguardManager.inKeyguardRestrictedInputMode()) {
            getWindow().addFlags(
                    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                            WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        } else {
            getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
                            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        }
    }

    private void acceptCall() {

        // for HTC devices we need to broadcast a connected headset
        boolean broadcastConnected = MANUFACTURER_HTC.equalsIgnoreCase(Build.MANUFACTURER)
                && !audioManager.isWiredHeadsetOn();

        if (broadcastConnected) {
            broadcastHeadsetConnected(false);
        }

        try {
            try {
                Log.d("AnswerCall","execute input keycode headset hook");
                //Turn on speaker
                audioManager.setMode(AudioManager.MODE_IN_CALL);
                if (!audioManager.isSpeakerphoneOn())
                    audioManager.setSpeakerphoneOn(true);
                audioManager.setMode(AudioManager.MODE_NORMAL);
                Runtime.getRuntime().exec("input keyevent " +
                        Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));

            } catch (IOException e) {
                // Runtime.exec(String) had an I/O problem, try to fall back
                Log.d("AnswerCall","send keycode headset hook intents");
                String enforcedPerm = "android.permission.CALL_PRIVILEGED";
                Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(
                        Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN,
                                KeyEvent.KEYCODE_HEADSETHOOK));
                Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(
                        Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP,
                                KeyEvent.KEYCODE_HEADSETHOOK));

                sendOrderedBroadcast(btnDown, enforcedPerm);
                sendOrderedBroadcast(btnUp, enforcedPerm);
            }
        } finally {
            if (broadcastConnected) {
                broadcastHeadsetConnected(false);
            }
        }
    }

    private void broadcastHeadsetConnected(boolean connected) {
        Intent i = new Intent(Intent.ACTION_HEADSET_PLUG);
        i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        i.putExtra("state", connected ? 1 : 0);
        i.putExtra("name", "mysms");
        try {
            sendOrderedBroadcast(i, null);
        } catch (Exception e) {
        }
    }


    private class CallStateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    }
}

https://dev59.com/RnHYa4cB1Zd3GeqPKVY2 - 7geeky
我之前尝试过那个链接,但它对我的手机无效。 - Jame
如果您正在使用API级别>= 23,则还要检查运行时权限,如果可能的话,请检查logcat,您可能会收到任何类型的错误或警告,请在此处放置它。 - Vickyexpert
@Vickyexpert:抱歉回复晚了。我尝试显示日志或警告,但没有警告。我正在使用Android 21级别。我无法打开答录机GUI的说话功能。 - Jame
我不确定是否可以使用SDK完成,但是您可以使用Xposed模块来完成。 - Dmytro Rostopira
2个回答

14

最终,我找到了解决方案。我将上面的代码放在一个线程内运行,它很好地工作了。这是我的代码。希望它可以帮助别人。

            Thread thread = new Thread() {
                @Override
                public void run() {
                    try {
                        while(true) {
                            sleep(1000);
                            audioManager.setMode(AudioManager.MODE_IN_CALL);
                            if (!audioManager.isSpeakerphoneOn())
                                audioManager.setSpeakerphoneOn(true);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };

            thread.start();

嗨@jame, 我正在尝试完成类似的事情。我有几部电话,铃声不响,我正在开发一个应用程序,在我接到电话时启用扬声器,当我把它靠近耳朵时,传感器会关闭显示屏,并将扬声器切换到耳机。有什么解决方案吗? - CodyMan
3
为什么需要使用线程?为什么不能在UI线程上运行就行了?这对我来说很有效... - android developer
你在安卓10上能用吗?对我来说它没有工作。请给予建议。 - RaRa
1
这是胡说八道...我们为什么需要这样做。到底怎么回事???我以为某个方法只是在电话应用程序上切换扬声器模式开关或类似的东西!至少能工作哈哈。谢谢! 编辑:实际上没有必要使用while循环。只需将其放入线程中即可。也许它只是不能在主线程上运行或类似的东西。有趣。终于可以工作了... - Edw590

-1
我找到了这个解决方案,希望能对你有所帮助。
final static int FOR_MEDIA = 1;

final static int FORCE_NONE = 0;

final static int FORCE_SPEAKER = 1;

Class audioSystemClass = Class.forName("android.media.AudioSystem");

Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class);

setForceUse.invoke(null, FOR_MEDIA, FORCE_SPEAKER);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接