32

I'm developing an application that has the following requisite: If there is a headset plugged in the device and the user removes it, I need to mute all streams. To do that I need to listen to the AudioManager.ACTION_AUDIO_BECOMING_NOISY Broadcast. This is ok! Not problem here.

But when the user plugs the headset again, I need to un-mute the device. But there isn't a AudioManager.ACTION_AUDIO_BECOMING_NOISY opposite broadcast. I cannot know when the headset is plugged again.

One solution is to periodically see if AudioManager.isWiredHeadsetOn() is true but this don't appear to be a good solution to me.

Is there a way to detect when the user plugs a headset on the device?

Edited: I tried to use Intent.ACTION_HEADSET_PLUG this way, but it didn't work.

In the manifest.xml I put:

<receiver android:name=".MusicIntentReceiver" >
    <intent-filter>
        <action android:name="android.intent.action.HEADSET_PLUG" />
    </intent-filter>
</receiver>

And here is the code of my MusicIntentReceiver.java:

public class MusicIntentReceiver extends BroadcastReceiver {

    public void onReceive(Context ctx, Intent intent) {
        AudioManager audioManager = (AudioManager)ctx.getSystemService(Context.AUDIO_SERVICE);
        if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
            Log.d("Let's turn the sound on!");
            //other things to un-mute the streams
        }
    }
}

Any other solution to try?

Renato Lochetti
  • 4,558
  • 3
  • 32
  • 49
  • 1
    You can not register the receiver for ACTION_HEADSET_PLUG in the manifest . It should be dynamically registered in the code .https://developer.android.com/reference/android/media/AudioManager.html#ACTION_HEADSET_PLUG – jkv Sep 26 '17 at 16:02

2 Answers2

90

How about this call: http://developer.android.com/reference/android/content/Intent.html#ACTION_HEADSET_PLUG which I found at Droid Incredible Headphones Detection ?

The updated code I see in your question now isn't enough. That broadcast happens when the plugged state changes, and sometimes when it doesn't, according to Intent.ACTION_HEADSET_PLUG is received when activity starts so I would write:

package com.example.testmbr;

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;

public class MainActivity extends Activity  {
private static final String TAG = "MainActivity";
private MusicIntentReceiver myReceiver;

@Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    myReceiver = new MusicIntentReceiver();
}

@Override public void onResume() {
    IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
    registerReceiver(myReceiver, filter);
    super.onResume();
}

private class MusicIntentReceiver extends BroadcastReceiver {
    @Override public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
            int state = intent.getIntExtra("state", -1);
            switch (state) {
            case 0:
                Log.d(TAG, "Headset is unplugged");
                break;
            case 1:
                Log.d(TAG, "Headset is plugged");
                break;
            default:
                Log.d(TAG, "I have no idea what the headset state is");
            }
        }
    }
}

@Override public void onPause() {
    unregisterReceiver(myReceiver);
    super.onPause();
}
}

The AudioManager.isWiredHeadsetOn() call which I earlier recommended turns out to be deprecated since API 14, so I replaced it with extracting the state from the broadcast intent. It's possible that there could be multiple broadcasts for each plugging or unplugging, perhaps because of contact bounce in the connector.

Community
  • 1
  • 1
emrys57
  • 6,679
  • 3
  • 39
  • 49
  • This did not solved the problem. See the edited question for more details. Did I use your solution correctly? – Renato Lochetti Nov 29 '12 at 10:56
  • The code cannot run only in the start of the Activity. I need to receive whenever the changes occur (what characterizes a Broadcast). The problem with the `Intent.ACTION_HEADSET_PLUG` is that my BroadcastReceiver does not receive the broadcast when the user plugs the headset. – Renato Lochetti Nov 29 '12 at 12:36
  • 1
    Did you register it to receive the broadcasts? `IntentFilter filter=new IntentFilter(AudioManager.ACTION_HEADSET_PLUG); registerReceiver(this,filter);` in the constructor of your MusicIntentReceiver. – emrys57 Nov 29 '12 at 13:31
  • 1
    In fact this Broadcast can only be received if we register a Receiver. It is `FLAG_RECEIVER_REGISTERED_ONLY`. We need to register a receiver in the first activity or in a Service. Can you update your answer with these information? – Renato Lochetti Nov 30 '12 at 11:43
  • 1
    Renato, does that code work for you? I tried it on my phone and it seems to work for me. – emrys57 Dec 01 '12 at 11:21
  • 1
    For anyone who is reading this, don't forget isInitialStickyBroadcast() or you are gonna have some trouble :) http://stackoverflow.com/a/4452190/1341947 – Ahmet Noyan Kızıltan Oct 27 '13 at 22:01
  • Hello @emrys57, I tries your code ( I gave same problem as my code), if you restart the device, this method will never run, unless the user insert the jack in or out. I needed to check if the jack is not presented, then mute the sound using audio.manager.Do you know how can you force this function to run without the state changed ? – Thiago Apr 09 '15 at 08:58
  • 1
    `AudioManager.isWiredheadSetOn` is deprecated but still works. The documentation at https://developer.android.com/reference/android/media/AudioManager.html#isWiredHeadsetOn%28%29 specifically recommends using it as a way to determine if the headset is plugged in. – emrys57 Apr 09 '15 at 09:01
  • this registers the broadcast receiver each and everytime when the user resumes the app and hence each and every time the player is paused or started ..how to handle this? –  Sep 28 '16 at 07:01
  • 1
    @HaraHaraMahadevaki: you can register it in onCreate and unregister in onDestroy. Or use a public flag for it. – ישו אוהב אותך Jun 08 '17 at 03:10
  • This is so helpful and easy to implement and working fine. – Parth Patel Aug 04 '18 at 11:15
2

I haven't worked with this, but if I'm reading the docs right, ACTION_AUDIO_BECOMING_NOISY is for letting an app know that the audio input might start hearing the audio output. When you unplug the headset, the phone's mic might start picking up the phone's speaker, hence the message.

On the other hand, ACTION_SCO_AUDIO_STATE_UPDATED is designed to let you know when there is a change in the connection state of a bluetooth device.

That second one is probably what you want to listen for.

Steve Blackwell
  • 5,904
  • 32
  • 49
  • Is this action only for bluetooth headsets? Do you think it'll work with jack plugged headsets? – Renato Lochetti Nov 29 '12 at 10:59
  • I think this is just for bluetooth devices that are connecting/disconnecting. For the audio jack plug, try listening for the [`ACTION_HEADSET_PLUG`](https://developer.android.com/reference/android/content/Intent.html#ACTION_HEADSET_PLUG) intent. – Steve Blackwell Nov 29 '12 at 21:05
  • No it is for jack plugged headsets as well. – varunkr Apr 15 '16 at 01:36