/*
|
* Copyright (c) 2010-2019 Belledonne Communications SARL.
|
*
|
* This file is part of linphone-android
|
* (see https://www.linphone.org).
|
*
|
* This program is free software: you can redistribute it and/or modify
|
* it under the terms of the GNU General Public License as published by
|
* the Free Software Foundation, either version 3 of the License, or
|
* (at your option) any later version.
|
*
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
*
|
* You should have received a copy of the GNU General Public License
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
*/
|
package org.linphone.call;
|
|
import static android.media.AudioManager.MODE_RINGTONE;
|
import static android.media.AudioManager.STREAM_RING;
|
import static android.media.AudioManager.STREAM_VOICE_CALL;
|
|
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothHeadset;
|
import android.bluetooth.BluetoothProfile;
|
import android.content.Context;
|
import android.content.Intent;
|
import android.content.IntentFilter;
|
import android.media.AudioManager;
|
import android.media.MediaPlayer;
|
import android.net.Uri;
|
import android.os.Vibrator;
|
import android.provider.Settings;
|
import android.telephony.TelephonyManager;
|
import android.view.KeyEvent;
|
import java.io.FileInputStream;
|
import java.io.IOException;
|
import java.util.List;
|
import org.linphone.LinphoneContext;
|
import org.linphone.LinphoneManager;
|
import org.linphone.R;
|
import org.linphone.compatibility.Compatibility;
|
import org.linphone.core.Address;
|
import org.linphone.core.Call;
|
import org.linphone.core.Core;
|
import org.linphone.core.CoreListenerStub;
|
import org.linphone.core.EcCalibratorStatus;
|
import org.linphone.core.tools.Log;
|
import org.linphone.receivers.BluetoothReceiver;
|
import org.linphone.receivers.HeadsetReceiver;
|
import org.linphone.settings.LinphonePreferences;
|
|
public class AndroidAudioManager {
|
private Context mContext;
|
private AudioManager mAudioManager;
|
private Call mRingingCall;
|
private MediaPlayer mRingerPlayer;
|
private final Vibrator mVibrator;
|
private BluetoothAdapter mBluetoothAdapter;
|
private BluetoothHeadset mBluetoothHeadset;
|
private BluetoothReceiver mBluetoothReceiver;
|
private HeadsetReceiver mHeadsetReceiver;
|
private boolean mHeadsetReceiverRegistered;
|
|
private boolean mIsRinging;
|
private boolean mAudioFocused;
|
private boolean mEchoTesterIsRunning;
|
private boolean mIsBluetoothHeadsetConnected;
|
private boolean mIsBluetoothHeadsetScoConnected;
|
|
private CoreListenerStub mListener;
|
|
public AndroidAudioManager(Context context) {
|
mContext = context;
|
mAudioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE));
|
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
mEchoTesterIsRunning = false;
|
mHeadsetReceiverRegistered = false;
|
|
startBluetooth();
|
|
mListener =
|
new CoreListenerStub() {
|
@Override
|
public void onCallStateChanged(
|
final Core core,
|
final Call call,
|
final Call.State state,
|
final String message) {
|
if (state == Call.State.IncomingReceived
|
|| (state == Call.State.IncomingEarlyMedia
|
&& mContext.getResources()
|
.getBoolean(
|
R.bool.allow_ringing_while_early_media))) {
|
// Brighten screen for at least 10 seconds
|
if (core.getCallsNb() == 1) {
|
requestAudioFocus(STREAM_RING);
|
|
mRingingCall = call;
|
startRinging(call.getRemoteAddress());
|
// otherwise there is the beep
|
}
|
} else if (call == mRingingCall && mIsRinging) {
|
// previous state was ringing, so stop ringing
|
stopRinging();
|
}
|
|
if (state == Call.State.Connected) {
|
if (core.getCallsNb() == 1) {
|
// It is for incoming calls, because outgoing calls enter
|
// MODE_IN_COMMUNICATION immediately when they start.
|
// However, incoming call first use the MODE_RINGING to play the
|
// local ring.
|
if (call.getDir() == Call.Dir.Incoming) {
|
setAudioManagerInCallMode();
|
// mAudioManager.abandonAudioFocus(null);
|
requestAudioFocus(STREAM_VOICE_CALL);
|
}
|
if (!mIsBluetoothHeadsetConnected) {
|
if (mContext.getResources().getBoolean(R.bool.isTablet)) {
|
routeAudioToSpeaker();
|
} else {
|
// Only force earpiece audio route for incoming audio calls,
|
// outgoing calls may have manually enabled speaker
|
if (call.getDir() == Call.Dir.Incoming) {
|
routeAudioToEarPiece();
|
}
|
}
|
}
|
// Only register this one when a call is active
|
|
enableHeadsetReceiver();
|
}
|
} else if (state == Call.State.End || state == Call.State.Error) {
|
if (core.getCallsNb() == 0) {
|
if (mAudioFocused) {
|
int res = mAudioManager.abandonAudioFocus(null);
|
Log.d(
|
"[Audio Manager] Audio focus released a bit later: "
|
+ (res
|
== AudioManager
|
.AUDIOFOCUS_REQUEST_GRANTED
|
? "Granted"
|
: "Denied"));
|
mAudioFocused = false;
|
}
|
|
// Only register this one when a call is active
|
if (mHeadsetReceiver != null && mHeadsetReceiverRegistered) {
|
Log.i("[Audio Manager] Unregistering headset receiver");
|
mContext.unregisterReceiver(mHeadsetReceiver);
|
mHeadsetReceiverRegistered = false;
|
}
|
|
TelephonyManager tm =
|
(TelephonyManager)
|
mContext.getSystemService(
|
Context.TELEPHONY_SERVICE);
|
if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
|
Log.d(
|
"[Audio Manager] ---AndroidAudioManager: back to MODE_NORMAL");
|
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
Log.d(
|
"[Audio Manager] All call terminated, routing back to earpiece");
|
routeAudioToEarPiece();
|
}
|
}
|
}
|
if (state == Call.State.OutgoingInit) {
|
// Enter the MODE_IN_COMMUNICATION mode as soon as possible, so that
|
// ringback is heard normally in earpiece or bluetooth receiver.
|
setAudioManagerInCallMode();
|
requestAudioFocus(STREAM_VOICE_CALL);
|
if (mIsBluetoothHeadsetConnected) {
|
routeAudioToBluetooth();
|
}
|
}
|
|
if (state == Call.State.StreamsRunning) {
|
setAudioManagerInCallMode();
|
if (mIsBluetoothHeadsetConnected) {
|
routeAudioToBluetooth();
|
}
|
}
|
}
|
|
@Override
|
public void onEcCalibrationResult(
|
Core core, EcCalibratorStatus status, int delay_ms) {
|
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
mAudioManager.abandonAudioFocus(null);
|
Log.i("[Audio Manager] Set audio mode on 'Normal'");
|
}
|
};
|
|
Core core = LinphoneManager.getCore();
|
if (core != null) {
|
core.addListener(mListener);
|
}
|
}
|
|
public void destroy() {
|
if (mBluetoothAdapter != null && mBluetoothHeadset != null) {
|
Log.i("[Audio Manager] [Bluetooth] Closing HEADSET profile proxy");
|
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
}
|
|
Log.i("[Audio Manager] [Bluetooth] Unegistering bluetooth receiver");
|
if (mBluetoothReceiver != null) {
|
mContext.unregisterReceiver(mBluetoothReceiver);
|
}
|
|
Core core = LinphoneManager.getCore();
|
if (core != null) {
|
core.removeListener(mListener);
|
}
|
}
|
|
/* Audio routing */
|
|
public void setAudioManagerModeNormal() {
|
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
}
|
|
public void routeAudioToEarPiece() {
|
routeAudioToSpeakerHelper(false);
|
}
|
|
public void routeAudioToSpeaker() {
|
routeAudioToSpeakerHelper(true);
|
}
|
|
public boolean isAudioRoutedToSpeaker() {
|
return mAudioManager.isSpeakerphoneOn() && !isUsingBluetoothAudioRoute();
|
}
|
|
public boolean isAudioRoutedToEarpiece() {
|
return !mAudioManager.isSpeakerphoneOn() && !isUsingBluetoothAudioRoute();
|
}
|
|
/* Echo cancellation */
|
|
public void startEcCalibration() {
|
Core core = LinphoneManager.getCore();
|
if (core == null) {
|
return;
|
}
|
|
routeAudioToSpeaker();
|
setAudioManagerInCallMode();
|
Log.i("[Audio Manager] Set audio mode on 'Voice Communication'");
|
requestAudioFocus(STREAM_VOICE_CALL);
|
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
|
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
|
core.startEchoCancellerCalibration();
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0);
|
}
|
|
public void startEchoTester() {
|
Core core = LinphoneManager.getCore();
|
if (core == null) {
|
return;
|
}
|
|
routeAudioToSpeaker();
|
setAudioManagerInCallMode();
|
Log.i("[Audio Manager] Set audio mode on 'Voice Communication'");
|
requestAudioFocus(STREAM_VOICE_CALL);
|
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
int sampleRate;
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
|
String sampleRateProperty =
|
mAudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
|
sampleRate = Integer.parseInt(sampleRateProperty);
|
core.startEchoTester(sampleRate);
|
mEchoTesterIsRunning = true;
|
}
|
|
public void stopEchoTester() {
|
Core core = LinphoneManager.getCore();
|
if (core == null) {
|
return;
|
}
|
|
mEchoTesterIsRunning = false;
|
core.stopEchoTester();
|
routeAudioToEarPiece();
|
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
Log.i("[Audio Manager] Set audio mode on 'Normal'");
|
}
|
|
public boolean getEchoTesterStatus() {
|
return mEchoTesterIsRunning;
|
}
|
|
public boolean onKeyVolumeAdjust(int keyCode) {
|
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
|
adjustVolume(1);
|
return true;
|
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
adjustVolume(-1);
|
return true;
|
}
|
return false;
|
}
|
|
private void setAudioManagerInCallMode() {
|
if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
|
Log.w("[Audio Manager] already in MODE_IN_COMMUNICATION, skipping...");
|
return;
|
}
|
Log.d("[Audio Manager] Mode: MODE_IN_COMMUNICATION");
|
|
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
}
|
|
private void requestAudioFocus(int stream) {
|
if (!mAudioFocused) {
|
int res =
|
mAudioManager.requestAudioFocus(
|
null, stream, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);
|
Log.d(
|
"[Audio Manager] Audio focus requested: "
|
+ (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
? "Granted"
|
: "Denied"));
|
if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) mAudioFocused = true;
|
}
|
}
|
|
private synchronized void startRinging(Address remoteAddress) {
|
if (!LinphonePreferences.instance().isDeviceRingtoneEnabled()) {
|
// Enable speaker audio route, linphone library will do the ringing itself automatically
|
routeAudioToSpeaker();
|
return;
|
}
|
|
boolean doNotDisturbPolicyAllowsRinging =
|
Compatibility.isDoNotDisturbPolicyAllowingRinging(mContext, remoteAddress);
|
if (!doNotDisturbPolicyAllowsRinging) {
|
Log.e("[Audio Manager] Do not ring as Android Do Not Disturb Policy forbids it");
|
return;
|
}
|
|
routeAudioToSpeaker();
|
mAudioManager.setMode(MODE_RINGTONE);
|
|
try {
|
if ((mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE
|
|| mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL)
|
&& mVibrator != null
|
&& LinphonePreferences.instance().isIncomingCallVibrationEnabled()) {
|
Compatibility.vibrate(mVibrator);
|
}
|
if (mRingerPlayer == null) {
|
requestAudioFocus(STREAM_RING);
|
mRingerPlayer = new MediaPlayer();
|
mRingerPlayer.setAudioStreamType(STREAM_RING);
|
|
String ringtone =
|
LinphonePreferences.instance()
|
.getRingtone(Settings.System.DEFAULT_RINGTONE_URI.toString());
|
try {
|
if (ringtone.startsWith("content://")) {
|
mRingerPlayer.setDataSource(mContext, Uri.parse(ringtone));
|
} else {
|
FileInputStream fis = new FileInputStream(ringtone);
|
mRingerPlayer.setDataSource(fis.getFD());
|
fis.close();
|
}
|
} catch (IOException e) {
|
Log.e(e, "[Audio Manager] Cannot set ringtone");
|
}
|
|
mRingerPlayer.prepare();
|
mRingerPlayer.setLooping(true);
|
mRingerPlayer.start();
|
} else {
|
Log.w("[Audio Manager] Already ringing");
|
}
|
} catch (Exception e) {
|
Log.e(e, "[Audio Manager] Cannot handle incoming call");
|
}
|
mIsRinging = true;
|
}
|
|
private synchronized void stopRinging() {
|
if (mRingerPlayer != null) {
|
mRingerPlayer.stop();
|
mRingerPlayer.release();
|
mRingerPlayer = null;
|
}
|
if (mVibrator != null) {
|
mVibrator.cancel();
|
}
|
|
mIsRinging = false;
|
}
|
|
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
Log.w("[Audio Manager] Routing audio to " + (speakerOn ? "speaker" : "earpiece"));
|
if (mIsBluetoothHeadsetScoConnected) {
|
Log.w("[Audio Manager] [Bluetooth] Disabling bluetooth audio route");
|
changeBluetoothSco(false);
|
}
|
|
mAudioManager.setSpeakerphoneOn(speakerOn);
|
}
|
|
private void adjustVolume(int i) {
|
if (mAudioManager.isVolumeFixed()) {
|
Log.e("[Audio Manager] Can't adjust volume, device has it fixed...");
|
// Keep going just in case...
|
}
|
|
int stream = STREAM_VOICE_CALL;
|
if (mIsBluetoothHeadsetScoConnected) {
|
Log.i(
|
"[Audio Manager] Bluetooth is connected, try to change the volume on STREAM_BLUETOOTH_SCO");
|
stream = 6; // STREAM_BLUETOOTH_SCO, it's hidden...
|
}
|
|
// starting from ICS, volume must be adjusted by the application,
|
// at least for STREAM_VOICE_CALL volume stream
|
mAudioManager.adjustStreamVolume(
|
stream,
|
i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE,
|
AudioManager.FLAG_SHOW_UI);
|
}
|
|
// Bluetooth
|
|
public synchronized void bluetoothHeadetConnectionChanged(boolean connected) {
|
mIsBluetoothHeadsetConnected = connected;
|
mAudioManager.setBluetoothScoOn(connected);
|
if (LinphoneContext.isReady()) LinphoneManager.getCallManager().refreshInCallActions();
|
}
|
|
public synchronized void bluetoothHeadetAudioConnectionChanged(boolean connected) {
|
mIsBluetoothHeadsetScoConnected = connected;
|
mAudioManager.setBluetoothScoOn(connected);
|
}
|
|
public synchronized boolean isBluetoothHeadsetConnected() {
|
return mIsBluetoothHeadsetConnected;
|
}
|
|
public synchronized void bluetoothHeadetScoConnectionChanged(boolean connected) {
|
mIsBluetoothHeadsetScoConnected = connected;
|
if (LinphoneContext.isReady()) LinphoneManager.getCallManager().refreshInCallActions();
|
}
|
|
public synchronized boolean isUsingBluetoothAudioRoute() {
|
return mIsBluetoothHeadsetScoConnected;
|
}
|
|
public synchronized void routeAudioToBluetooth() {
|
if (!isBluetoothHeadsetConnected()) {
|
Log.w("[Audio Manager] [Bluetooth] No headset connected");
|
return;
|
}
|
if (mAudioManager.getMode() != AudioManager.MODE_IN_COMMUNICATION) {
|
Log.w(
|
"[Audio Manager] [Bluetooth] Changing audio mode to MODE_IN_COMMUNICATION and requesting STREAM_VOICE_CALL focus");
|
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
requestAudioFocus(STREAM_VOICE_CALL);
|
}
|
changeBluetoothSco(true);
|
}
|
|
private synchronized void changeBluetoothSco(final boolean enable) {
|
// IT WILL TAKE A CERTAIN NUMBER OF CALLS TO EITHER START/STOP BLUETOOTH SCO FOR IT TO WORK
|
if (enable && mIsBluetoothHeadsetScoConnected) {
|
Log.i("[Audio Manager] [Bluetooth] SCO already enabled, skipping");
|
return;
|
} else if (!enable && !mIsBluetoothHeadsetScoConnected) {
|
Log.i("[Audio Manager] [Bluetooth] SCO already disabled, skipping");
|
return;
|
}
|
|
new Thread() {
|
@Override
|
public void run() {
|
Log.i("[Audio Manager] [Bluetooth] SCO start/stop thread started");
|
boolean resultAcknowledged;
|
int retries = 0;
|
|
do {
|
try {
|
Thread.sleep(200);
|
} catch (InterruptedException e) {
|
Log.e(e);
|
}
|
|
synchronized (AndroidAudioManager.this) {
|
if (enable) {
|
Log.i(
|
"[Audio Manager] [Bluetooth] Starting SCO: try number "
|
+ retries);
|
mAudioManager.startBluetoothSco();
|
} else {
|
Log.i(
|
"[Audio Manager] [Bluetooth] Stopping SCO: try number "
|
+ retries);
|
mAudioManager.stopBluetoothSco();
|
}
|
resultAcknowledged = isUsingBluetoothAudioRoute() == enable;
|
retries++;
|
}
|
} while (!resultAcknowledged && retries < 10);
|
}
|
}.start();
|
}
|
|
public void bluetoothAdapterStateChanged() {
|
if (mBluetoothAdapter.isEnabled()) {
|
Log.i("[Audio Manager] [Bluetooth] Adapter enabled");
|
mIsBluetoothHeadsetConnected = false;
|
mIsBluetoothHeadsetScoConnected = false;
|
|
BluetoothProfile.ServiceListener bluetoothServiceListener =
|
new BluetoothProfile.ServiceListener() {
|
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
if (profile == BluetoothProfile.HEADSET) {
|
Log.i("[Audio Manager] [Bluetooth] HEADSET profile connected");
|
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
|
List<BluetoothDevice> devices =
|
mBluetoothHeadset.getConnectedDevices();
|
if (devices.size() > 0) {
|
Log.i(
|
"[Audio Manager] [Bluetooth] A device is already connected");
|
bluetoothHeadetConnectionChanged(true);
|
}
|
|
Log.i("[Audio Manager] [Bluetooth] Registering bluetooth receiver");
|
|
IntentFilter filter = new IntentFilter();
|
filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
|
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
|
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
|
filter.addAction(
|
BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
|
|
Intent sticky =
|
mContext.registerReceiver(mBluetoothReceiver, filter);
|
Log.i("[Audio Manager] [Bluetooth] Bluetooth receiver registered");
|
int state =
|
sticky.getIntExtra(
|
AudioManager.EXTRA_SCO_AUDIO_STATE,
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
Log.i(
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connected");
|
bluetoothHeadetScoConnectionChanged(true);
|
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
Log.i(
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO disconnected");
|
bluetoothHeadetScoConnectionChanged(false);
|
} else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTING) {
|
Log.i(
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connecting");
|
} else if (state == AudioManager.SCO_AUDIO_STATE_ERROR) {
|
Log.i(
|
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connection error");
|
} else {
|
Log.w(
|
"[Audio Manager] [Bluetooth] Bluetooth headset unknown SCO state changed: "
|
+ state);
|
}
|
}
|
}
|
|
public void onServiceDisconnected(int profile) {
|
if (profile == BluetoothProfile.HEADSET) {
|
Log.i("[Audio Manager] [Bluetooth] HEADSET profile disconnected");
|
mBluetoothHeadset = null;
|
mIsBluetoothHeadsetConnected = false;
|
mIsBluetoothHeadsetScoConnected = false;
|
}
|
}
|
};
|
|
mBluetoothAdapter.getProfileProxy(
|
mContext, bluetoothServiceListener, BluetoothProfile.HEADSET);
|
} else {
|
Log.w("[Audio Manager] [Bluetooth] Adapter disabled");
|
}
|
}
|
|
private void startBluetooth() {
|
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
if (mBluetoothAdapter != null) {
|
Log.i("[Audio Manager] [Bluetooth] Adapter found");
|
if (mAudioManager.isBluetoothScoAvailableOffCall()) {
|
Log.i("[Audio Manager] [Bluetooth] SCO available off call, continue");
|
} else {
|
Log.w("[Audio Manager] [Bluetooth] SCO not available off call !");
|
}
|
|
mBluetoothReceiver = new BluetoothReceiver();
|
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
|
mContext.registerReceiver(mBluetoothReceiver, filter);
|
|
bluetoothAdapterStateChanged();
|
}
|
}
|
|
// HEADSET
|
|
private void enableHeadsetReceiver() {
|
mHeadsetReceiver = new HeadsetReceiver();
|
|
Log.i("[Audio Manager] Registering headset receiver");
|
mContext.registerReceiver(
|
mHeadsetReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
|
mContext.registerReceiver(
|
mHeadsetReceiver, new IntentFilter(AudioManager.ACTION_HEADSET_PLUG));
|
mHeadsetReceiverRegistered = true;
|
}
|
}
|