Detect headphones Android - android

I program in recent years to Android and I wonder something:
How to detect the presence of headphones?
There is a method: isWiredHeadsetOn() but it doesn't work.
I've tried that but it doesn't work:
AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
Log.i("am.isWiredHeadsetOn()", am.isWiredHeadsetOn() + "");
if (am.isWiredHeadsetOn()) {
//code
}
Thank you (and sorry if I made spelling mistakes, I am French)

#Phil answer at https://stackoverflow.com/a/19102661/4758255 is a good implementation to detect the headphone.
Here I'm quoting from his answer. Please upvoted his answer not this!
Upvote the answer: https://stackoverflow.com/a/19102661/4758255
I've had an app in the store for three years that monitors both the wired headset and bluetooth state and nobody has ever complained about battery drain. But that is because I am successfully using a single service and broadcast receiver for detecting events from both. Here's the two key classes:
public class HeadsetStateBroadcastReceiver extends BroadcastReceiver {
public static final String[] HEADPHONE_ACTIONS = {
Intent.ACTION_HEADSET_PLUG,
"android.bluetooth.headset.action.STATE_CHANGED",
"android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED"
};
#Override
public void onReceive(final Context context, final Intent intent) {
boolean broadcast = false;
// Wired headset monitoring
if (intent.getAction().equals(HEADPHONE_ACTIONS[0]) {
final int state = intent.getIntExtra("state", 0);
AudioPreferences.setWiredHeadphoneState(context, state > 0);
broadcast = true;
}
// Bluetooth monitoring
// Works up to and including Honeycomb
if (intent.getAction().equals(HEADPHONE_ACTIONS[1])) {
int state = intent.getIntExtra("android.bluetooth.headset.extra.STATE", 0);
AudioPreferences.setBluetoothHeadsetState(context, state == 2);
broadcast = true;
}
// Works for Ice Cream Sandwich
if (intent.getAction().equals(HEADPHONE_ACTIONS[2])) {
int state = intent.getIntExtra("android.bluetooth.profile.extra.STATE", 0);
AudioPreferences.setBluetoothHeadsetState(context, state == 2);
broadcast = true;
}
// Used to inform interested activities that the headset state has changed
if (broadcast) {
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("headsetStateChange"));
}
}
}
Here is the service I use to register the broadcast receiver:
public class HeadsetMonitoringService extends Service {
HeadsetStateBroadcastReceiver headsetStateReceiver;
#Override
public void onCreate() {
headsetStateReceiver = new HeadsetStateBroadcastReceiver();
final IntentFilter filter = new IntentFilter();
for (String action: HeadsetStateBroadcastReceiver.HEADPHONE_ACTIONS) {
filter.addAction(action);
}
registerReceiver(headsetStateReceiver, filter);
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
unregisterReceiver(headsetStateReceiver);
}
#Override
public IBinder onBind(final Intent intent) {
return null;
}
}
And here is my manifest entry:
<service
android:name=".services.HeadsetMonitoringService"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="initialiseHeadsetService" />
</intent-filter>
</service>
How it works is as follows:
I use an on boot broadcast receiver to send a start service message to the HeadsetMonitoringService (you don't have to do it this way, you could just do this when your application starts instead). The HeadsetMonitoringService in turn registers an instance of a broadcast listener that listens to all the headset events I am interested in - they are held in the HEADPHONE_ACTIONS array. Because the service is sticky it hangs around - and therefore so does the broadcast listener. But because both the service and the broadcast listener are event driven they do not consume any power until a headset state change occurs. Additionally, because the service is sticky, it will be restarted by the OS if it dies unexpectedly.
Whenever I receive a headset state change event I also fire a local broadcast so that interested activities can check the new state and take action if required.
For completeness, I should point out that I use another class (not shown here), AudioPreferences, to store as preferences both the Bluetooth and wired headset state, which can then be accessed whenever I need to know the headset state.
Your application will need the android.permission.BLUETOOTH permission if you are interested in the state of a Bluetooth headset. If not, just take out the Bluetooth related actions from the HEADPHONE_ACTIONS array and delete the associated if blocks from the onReceive method.

If you are OK with Marshmallow and up the AudioDeviceCallback might be what you are looking for. It works with an AudioManager and tells you when anything connects and disconnects.

AudioManager.isWiredHeadsetOn() appeared to be the right thing to do. According to the Android developer doc :
Checks whether a wired headset is connected or not.
This is not a valid indication that audio playback is actually over the wired headset as audio routing depends on other conditions.
Returns
true if a wired headset is connected. false if otherwise
But :
you have to add the associated permission to your manifest (MODIFY_AUDIO_SETTINGS)
according to this post, it doesn't work well with Bluetooth headset.

Related

Broadcast receiver to detect Sip Session

My Android application is continuously using the microphone and wants to release the microphone to other applications such as VOIP Calls.
I have registered broadcast receiver in the Manifest. But the microphone is not getting released.No sim card in the phones, I am only interested in detecting SIP sessions.
Here is my code in the Manifest
<receiver
android:name=".SipCallReceiver"
android:enabled="true"
android:exported="true">
</receiver>
Broadcastreceiver class
public class SipCallReceiver extends BroadcastReceiver {
ListeningActivity LA = new ListeningActivity();
#Override
public void onReceive(Context context, Intent intent) {
SipAudioCall call = null;
final SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onCallEnded(SipAudioCall call) {
LA.setflgphone(false); LA.onPstop();
}
#Override
public void onCallEstablished (SipAudioCall call) {
LA.setflgphone(true); LA.Lstop();
}
};
}
}
Can anyone please let me know the mistake I am making here.
Thank you
I was able to solve it.
I created two services.
The first service monitors the Audio Manager at schedule interval with ScheduledExecutorService. This will get the mode of the Audio Manager.
When there is no communication, the mode will be 0.
This status broadcast to a locally registered broadcast receiver. The broadcast receiver will stop and start the second service which using the microphone depending on the audio mode.

Way to ensure delivery of Action HEADSET_PLUG for ZTE T815 Android phone

I have registered a BroadcastReceiver to receive ACTION_HEADSET_PLUG which works fine for most devices, ie it is called whenever the headset is plugged or unplugged. But on others eg the ZTE T815, the Intent is never sent/received when the headset is plugged/unplugged.
For reference here is the code for the receiver registration:
private final BroadcastReceiver headsetPlugReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received intent=" + intent);
if (intent.getAction().equalsIgnoreCase(Intent.ACTION_HEADSET_PLUG)) {
// do stuff
}
}
};
public void onCreate(Bundle savedState) {
super.onCeate(savedState);
// ...
registerReceiver(headsetPlugReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
}
Further info:
The Intent is dispatched but only after the HEADSET_HOOK command is fired on the headset.
And when the Intent is dispatched
final int microphone = intent.getIntExtra("microphone", 0);
always returns 0 (ie no microphone).
So
Is there some config/code that can force the delivery of this
Intent?
How do I get the Intent to correctly report whether a
microphone exists or not?
It turns out the ZTE T815 has an OMTP TRRS config for its audio socket instead of CTIA/AHJ like every other modern Android device.
See http://en.wikipedia.org/wiki/Phone_connector_%28audio%29
A sad state of affairs, especially when trying to use audio feed inpout across products.

call broadcast receiver random times when wi-fi state change in android 4.2.2

My goal is print log when change wi-fi state.
I use below code.
MainActivity.java (Main Activity)
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this,WiFiService.class));
}
#Override
protected void onStart()
{
super.onStart();
Log.d("Start Service", "Start Service");;
startService(new Intent(this,WiFiService.class));
}
}
WiFiService.java (Service)
public class WiFiService extends Service
{
WiFiBroadCasetReceiver brod;
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
brod=new WiFiBroadCasetReceiver();
this.registerReceiver(brod, new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION));
}
#Override
public void onDestroy()
{
super.onDestroy();
}
}
WiFiBroadCasetReceiver.java (BroadcastReceiver)
public class WiFiBroadCasetReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context arg0, Intent arg1)
{
Log.d("on receiver", "receiver");
}
}
AndroidManifest.xml
<application>
........
........
<receiver android:name=".WiFiBroadCasetReceiver" >
<intent-filter>
<action android:name="android.net.wifi.supplicant.STATE_CHANGE" />
</intent-filter>
</receiver>
</application>
Problem :
Above code is working fine in android 4.0 and lower versions. When I change state of wi-fi, broadcast receiver is call random times. So, log is print random times. I need only one time. It work fine all android version remains android 4.1.0. or higher version(Jelly Bean). I use android.net.wifi.WIFI_STATE_CHANGED. But still same error occur.
Several points should be addressed in your question.
First, you might be confusing the state of "android.net.wifi.supplicant.STATE_CHANGE" and "android.net.wifi.WIFI_STATE_CHANGED". And I think what you really want is the later one. See the comment from the source code.
/**
* Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
* enabling, disabling, or unknown. One extra provides this state as an int.
* Another extra provides the previous state, if available.
*
* #see #EXTRA_WIFI_STATE
* #see #EXTRA_PREVIOUS_WIFI_STATE
*/
#SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WIFI_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_STATE_CHANGED";
and
/**
* Broadcast intent action indicating that a connection to the supplicant has
* been established (and it is now possible
* to perform Wi-Fi operations) or the connection to the supplicant has been
* lost. One extra provides the connection state as a boolean, where {#code true}
* means CONNECTED.
* #see #EXTRA_SUPPLICANT_CONNECTED
*/
#SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
"android.net.wifi.supplicant.CONNECTION_CHANGE";
Second, why you got multiple broadcast callbacks? And the number of times is random? I think you might need to check your code carefully:
1. You start the service twice, once in Activity.onCreate() and once in Activity.onStart()
2. You register your broadcast receiver twice, once in AndroidManifest.xml and once in Service.onStart()
3. The most important thing is that you will create a new instance of your broadcast receiver instance in your Service.onStart(). That is to say, whenever your service is start, a new receiver will be created and registered. And looking back on 1, you see every time you bring you Activity back will call the service to start again.
So the random times of callback is because your bad code. Please just remove all the broadcast registers, left only the one in the AndroidManifest.xml
Finally, why you cannot make it work on JellyBean later? I think this is because you haven't specified the correct action. Please try "android.net.wifi.WIFI_STATE_CHANGED" instead of "android.net.wifi.supplicant.STATE_CHANGE" and try again.
The broadcast is received whenever the supplicant state of the wifi changes. Since over the course of establishing a connection this will change multiple times, multiple broadcasts are expected. (I remember having seen this on 2.3 devices also but I mostly use the connectivity change broadcast to check connectivity change so I might be incorrect).
The workaround you can do is, in your broadcast receiver check the extras include in the intent which indicates the SupplicantState. If the supplicant state in the extra is equal to SupplicantState.COMPLETED (wifi is connected and authenticated) then only implement your app logic otherwise ignore the broadcast.

How to detect headphone plug event in "offline" mode [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
I know how to detect headphone plug in event if my application is running. You have to register broadcast receiver for ACTION_HEADSET_PLUG. But you can't capture this action using Manifest declaration for broadcast receiver. Therefore the only option to capture headphone plug in event is background service. But it drains battery and so on.
I checked out some music players and figured out that they capture that event without any additional services. How do they do that? Any ideas?
I've had an app in the store for three years that monitors both the wired headset and bluetooth state and nobody has ever complained about battery drain. But that is because I am successfully using a single service and broadcast receiver for detecting events from both. Here's the two key classes:
public class HeadsetStateBroadcastReceiver extends BroadcastReceiver {
public static final String[] HEADPHONE_ACTIONS = {
Intent.ACTION_HEADSET_PLUG,
"android.bluetooth.headset.action.STATE_CHANGED",
"android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED"
};
#Override
public void onReceive(final Context context, final Intent intent) {
boolean broadcast = false;
// Wired headset monitoring
if (intent.getAction().equals(HEADPHONE_ACTIONS[0]) {
final int state = intent.getIntExtra("state", 0);
AudioPreferences.setWiredHeadphoneState(context, state > 0);
broadcast = true;
}
// Bluetooth monitoring
// Works up to and including Honeycomb
if (intent.getAction().equals(HEADPHONE_ACTIONS[1])) {
int state = intent.getIntExtra("android.bluetooth.headset.extra.STATE", 0);
AudioPreferences.setBluetoothHeadsetState(context, state == 2);
broadcast = true;
}
// Works for Ice Cream Sandwich
if (intent.getAction().equals(HEADPHONE_ACTIONS[2])) {
int state = intent.getIntExtra("android.bluetooth.profile.extra.STATE", 0);
AudioPreferences.setBluetoothHeadsetState(context, state == 2);
broadcast = true;
}
// Used to inform interested activities that the headset state has changed
if (broadcast) {
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("headsetStateChange"));
}
}
}
Here is the service I use to register the broadcast receiver:
public class HeadsetMonitoringService extends Service {
HeadsetStateBroadcastReceiver headsetStateReceiver;
#Override
public void onCreate() {
headsetStateReceiver = new HeadsetStateBroadcastReceiver();
final IntentFilter filter = new IntentFilter();
for (String action: HeadsetStateBroadcastReceiver.HEADPHONE_ACTIONS) {
filter.addAction(action);
}
registerReceiver(headsetStateReceiver, filter);
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
unregisterReceiver(headsetStateReceiver);
}
#Override
public IBinder onBind(final Intent intent) {
return null;
}
}
And here is my manifest entry:
<service
android:name=".services.HeadsetMonitoringService"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="initialiseHeadsetService" />
</intent-filter>
</service>
How it works is as follows:
I use an on boot broadcast receiver to send a start service message to the HeadsetMonitoringService (you don't have to do it this way, you could just do this when your application starts instead). The HeadsetMonitoringService in turn registers an instance of a broadcast listener that listens to all the headset events I am interested in - they are held in the HEADPHONE_ACTIONS array. Because the service is sticky it hangs around - and therefore so does the broadcast listener. But because both the service and the broadcast listener are event driven they do not consume any power until a headset state change occurs. Additionally, because the service is sticky, it will be restarted by the OS if it dies unexpectedly.
Whenever I receive a headset state change event I also fire a local broadcast so that interested activities can check the new state and take action if required.
For completeness, I should point out that I use another class (not shown here), AudioPreferences, to store as preferences both the Bluetooth and wired headset state, which can then be accessed whenever I need to know the headset state.
Your application will need the android.permission.BLUETOOTH permission if you are interested in the state of a Bluetooth headset. If not, just take out the Bluetooth related actions from the HEADPHONE_ACTIONS array and delete the associated if blocks from the onReceive method.

Intent.ACTION_HEADSET_PLUG is received when activity starts

I am trying to pause music that is playing when the headset is unplugged.
I have created a BroadcastReceiver that listens for ACTION_HEADSET_PLUG intents and acts upon them when the state extra is 0 (for unplugged). My problem is that an ACTION_HEADSET_PLUG intent is received by my BroadcastReceiver whenever the activity is started. This is not the behavior that I would expect. I would expect the Intent to be fired only when the headset is plugged in or unplugged.
Is there a reason that the ACTION_HEADSET_PLUG Intent is caught immediately after registering a receiver with that IntentFilter? Is there a clear way that I can work with this issue?
I would assume that since the default music player implements similar functionality when the headset is unplugged that it would be possible.
What am I missing?
This is the registration code
registerReceiver(new HeadsetConnectionReceiver(),
new IntentFilter(Intent.ACTION_HEADSET_PLUG));
This is the definition of HeadsetConnectionReceiver
public class HeadsetConnectionReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "ACTION_HEADSET_PLUG Intent received");
}
}
Thanks for the reply Jake. I should have updated the original post to indicate that I discovered the issue that I was having. After a bit of research, I discovered that the ACTION_HEADSET_PLUG Intent is broadcast using the sendStickyBroadcast method in Context.
Sticky Intents are held by the system after being broadcast. That Intent will be caught whenever a new BroadcastReceiver is registered to receive it. It is triggered immediately after registration containing the last updated value. In the case of the headset, this is useful to be able to determine that the headset is already plugged in when you first register your receiver.
This is the code that I used to receive the ACTION_HEADSET_PLUG Intent:
private boolean headsetConnected = false;
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("state")){
if (headsetConnected && intent.getIntExtra("state", 0) == 0){
headsetConnected = false;
if (isPlaying()){
stopStreaming();
}
} else if (!headsetConnected && intent.getIntExtra("state", 0) == 1){
headsetConnected = true;
}
}
}
I use a different approach to stop playback when headset is unplug. I do not want you to use it since you are already fine, but some other people may find it useful. If you get control of audio focus, then Android will send you an event audio becoming noisy, so if you write a receiver for this event it will look like
public void onReceive(Context context, Intent intent) {
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
if (isPlaying()){
stopStreaming();
}
}
}
I ran into the same issue. I'm not sure what causes it, but at least in my testing it seems to be consistent, which means you can work around it. I did just that by adding a boolean member variable that starts as true, and is set to false on the first onReceive(Context, Intent) call. This flag then controls whether I actually process the unplug event or not.
For your reference, here is the code I use to do just that, which is available in context here.
private boolean isFirst;
public void onReceive(Context context, Intent intent)
{
if(!isFirst)
{
// Do stuff...
}
else
{
Log.d("Hearing Saver", "First run receieved.");
isFirst = false;
}
}

Categories

Resources