简体   繁体   中英

Detect lack of earpiece (speakerphone only) on an Android device

I've got an app which displays a speakerphone toggle button when used on a phone. The toggle switches audio routing between the phone's earpiece and the speakerphone. However, when the app is run on a tablet (or any device which lacks an earpiece), I'd like to remove the toggle, since all audio is routed through the speakerphone.

Ideally, I'd like to use some kind of isEarpiecePresent() call, or maybe check a flag on some configuration object to find this information, but I can't find anything of the sort in the API.

I attempted to work around the issue by calling AudioManager.setSpeakerphoneOn(false) , then checking AudioManager.isSpeakerphoneOn() , hoping that it would still return true and I could key off of that. The system returned false , even though audio is still routing through the speaker.

I'm currently thinking of checking for telephony capability, even though that doesn't exactly fit. Any other ideas?

So the ugly part is - Google is ignoring the problem. The pretty part is that I managed to actually do the check for earpiece, and on 5/5 devices it worked fine (tested on 5.0, 5.1, 6.0). And again, the ugly part is that this is just bad, unstable code and that it's hacky, but until they publish a better API, I couldn't do much..

Here is the hack :

private Boolean mHasEarpiece = null; // intentionally 'B' instead of 'b'

public boolean hasEarpiece() {
    if (mHasEarpiece != null) {
        return mHasEarpiece;
    }

    // not calculated yet, do it now
    try {
        Method method = AudioManager.class.getMethod("getDevicesForStream", Integer.TYPE);
        Field field = AudioManager.class.getField("DEVICE_OUT_EARPIECE");
        int earpieceFlag = field.getInt(null);
        int bitmaskResult = (int) method.invoke(mAudioManager, AudioManager.STREAM_VOICE_CALL);

        // check if masked by the earpiece flag
        if ((bitmaskResult & earpieceFlag) == earpieceFlag) {
            mHasEarpiece = Boolean.TRUE;
        } else {
            mHasEarpiece = Boolean.FALSE;
        }
    } catch (Throwable error) {
        Log.e(TAG, "Error while checking earpiece! ", error);
        mHasEarpiece = Boolean.FALSE;
    }

    return mHasEarpiece;
}

I'm open for improvement edits if you have something better :)

I've researched this and unfortunately I can't find any API support for detecting whether an earpiece exists.

I've now raised this with Google as a feature request:
http://code.google.com/p/android/issues/detail?id=37623

If you agree with the feature, click on the star at the bottom of the Google issue page to vote for it!

Lots of users have raised the issue that Google Talk doesn't offer a speaker/earpiece toggle option, which perhaps suggests the absence of a suitable API...
http://code.google.com/p/android/issues/detail?id=19221

As a workaround you may wish to hide the feature on devices approximated by (all of these approaches have drawbacks):

  • those with extra large screens (ie tablets)
  • those with no telephony support
  • use a configurable white/blacklist of the main devices that do not have an earpiece.

FTR, if you use this answer to route audio to the earpiece, there don't seem to be any negative side affects running that code on the Xoom (OS 3.1) or the Samsung Galaxy Tab (OS 2.2) - the audio just continues to play through the external speaker. I haven't had a chance to test if there are any interactions with Bluetooth headsets yet.

As you may now be aware, this cannot be done using the current Android API.

The Audio Hardware interface is proprietary, ie written by the manufacturers for their hardware and has to support certain calls by the Android system to make it compatible with applications developed using the Android SDK.

Even if you find a way around the lack of API support for one device this may not work on all devices. Your AudioManager.setSpeakerphoneOn(false) example may very well work for devices as it all depends on how the Audio Hardware interface has been written. It would be my assumption that most tablets will treat audio routing for earpiece and speaker the same if there is no earpiece.

If you want to check out the Audio Hardware interface code for the Nexus 7, it's here

public boolean isEarPieceConnected() {
        AudioManager audio = (AudioManager) this
                .getSystemService(Context.AUDIO_SERVICE);
        if (audio.isWiredHeadsetOn()) {
            Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
            return true;
        } else {
            Toast.makeText(this, "Not Connected", Toast.LENGTH_SHORT).show();
            return false;
        }
    }

you can also check for audio.isSpeakerphoneOn()

I hope this works if i am getting your problem right.

You can check this by using Audio Manager

Audio Manager

and also look

Head Set Plugged

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM