| Index: trunk/src/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
|
| ===================================================================
|
| --- trunk/src/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java (revision 240884)
|
| +++ trunk/src/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java (working copy)
|
| @@ -4,6 +4,8 @@
|
|
|
| package org.chromium.media;
|
|
|
| +import android.bluetooth.BluetoothAdapter;
|
| +import android.bluetooth.BluetoothManager;
|
| import android.content.BroadcastReceiver;
|
| import android.content.ContentResolver;
|
| import android.content.Context;
|
| @@ -18,7 +20,8 @@
|
| import android.media.audiofx.AcousticEchoCanceler;
|
| import android.os.Build;
|
| import android.os.Handler;
|
| -import android.os.HandlerThread;
|
| +import android.os.Looper;
|
| +import android.os.Process;
|
| import android.provider.Settings;
|
| import android.util.Log;
|
|
|
| @@ -54,7 +57,6 @@
|
| }
|
|
|
| // Supported audio device types.
|
| - private static final int DEVICE_DEFAULT = -2;
|
| private static final int DEVICE_INVALID = -1;
|
| private static final int DEVICE_SPEAKERPHONE = 0;
|
| private static final int DEVICE_WIRED_HEADSET = 1;
|
| @@ -81,6 +83,24 @@
|
| DEVICE_BLUETOOTH_HEADSET,
|
| };
|
|
|
| + // The device does not have any audio device.
|
| + static final int STATE_NO_DEVICE_SELECTED = 0;
|
| + // The speakerphone is on and an associated microphone is used.
|
| + static final int STATE_SPEAKERPHONE_ON = 1;
|
| + // The phone's earpiece is on and an associated microphone is used.
|
| + static final int STATE_EARPIECE_ON = 2;
|
| + // A wired headset (with or without a microphone) is plugged in.
|
| + static final int STATE_WIRED_HEADSET_ON = 3;
|
| + // The audio stream is being directed to a Bluetooth headset.
|
| + static final int STATE_BLUETOOTH_ON = 4;
|
| + // We've requested that the audio stream be directed to Bluetooth, but
|
| + // have not yet received a response from the framework.
|
| + static final int STATE_BLUETOOTH_TURNING_ON = 5;
|
| + // We've requested that the audio stream stop being directed to
|
| + // Bluetooth, but have not yet received a response from the framework.
|
| + static final int STATE_BLUETOOTH_TURNING_OFF = 6;
|
| + // TODO(henrika): document the valid state transitions.
|
| +
|
| // Use 44.1kHz as the default sampling rate.
|
| private static final int DEFAULT_SAMPLING_RATE = 44100;
|
| // Randomly picked up frame size which is close to return value on N4.
|
| @@ -92,18 +112,15 @@
|
| private final Context mContext;
|
| private final long mNativeAudioManagerAndroid;
|
|
|
| - private int mSavedAudioMode = AudioManager.MODE_INVALID;
|
| -
|
| + private boolean mHasBluetoothPermission = false;
|
| private boolean mIsInitialized = false;
|
| private boolean mSavedIsSpeakerphoneOn;
|
| private boolean mSavedIsMicrophoneMute;
|
|
|
| - // Id of the requested audio device. Can only be modified by
|
| - // call to setDevice().
|
| - private int mRequestedAudioDevice = DEVICE_INVALID;
|
| + private Integer mAudioDeviceState = STATE_NO_DEVICE_SELECTED;
|
|
|
| - // Lock to protect |mAudioDevices| and |mRequestedAudioDevice| which can
|
| - // be accessed from the main thread and the audio manager thread.
|
| + // Lock to protect |mAudioDevices| which can be accessed from the main
|
| + // thread and the audio manager thread.
|
| private final Object mLock = new Object();
|
|
|
| // Contains a list of currently available audio devices.
|
| @@ -111,8 +128,9 @@
|
|
|
| private final ContentResolver mContentResolver;
|
| private SettingsObserver mSettingsObserver = null;
|
| - private HandlerThread mSettingsObserverThread = null;
|
| + private SettingsObserverThread mSettingsObserverThread = null;
|
| private int mCurrentVolume;
|
| + private final Object mSettingsObserverLock = new Object();
|
|
|
| // Broadcast receiver for wired headset intent broadcasts.
|
| private BroadcastReceiver mWiredHeadsetReceiver;
|
| @@ -139,31 +157,56 @@
|
| */
|
| @CalledByNative
|
| public void init() {
|
| - if (DEBUG) logd("init");
|
| if (mIsInitialized)
|
| return;
|
|
|
| - for (int i = 0; i < DEVICE_COUNT; ++i) {
|
| - mAudioDevices[i] = false;
|
| + synchronized (mLock) {
|
| + for (int i = 0; i < DEVICE_COUNT; ++i) {
|
| + mAudioDevices[i] = false;
|
| + }
|
| }
|
|
|
| + // Store microphone mute state and speakerphone state so it can
|
| + // be restored when closing.
|
| + mSavedIsSpeakerphoneOn = mAudioManager.isSpeakerphoneOn();
|
| + mSavedIsMicrophoneMute = mAudioManager.isMicrophoneMute();
|
| +
|
| + // Always enable speaker phone by default. This state might be reset
|
| + // by the wired headset receiver when it gets its initial sticky
|
| + // intent, if any.
|
| + setSpeakerphoneOn(true);
|
| + mAudioDeviceState = STATE_SPEAKERPHONE_ON;
|
| +
|
| // Initialize audio device list with things we know is always available.
|
| - if (hasEarpiece()) {
|
| - mAudioDevices[DEVICE_EARPIECE] = true;
|
| + synchronized (mLock) {
|
| + if (hasEarpiece()) {
|
| + mAudioDevices[DEVICE_EARPIECE] = true;
|
| + }
|
| + mAudioDevices[DEVICE_SPEAKERPHONE] = true;
|
| }
|
| - mAudioDevices[DEVICE_SPEAKERPHONE] = true;
|
|
|
| // Register receiver for broadcasted intents related to adding/
|
| // removing a wired headset (Intent.ACTION_HEADSET_PLUG).
|
| + // Also starts routing to the wired headset/headphone if one is
|
| + // already attached (can be overridden by a Bluetooth headset).
|
| registerForWiredHeadsetIntentBroadcast();
|
|
|
| - mSettingsObserverThread = new HandlerThread("SettingsObserver");
|
| - mSettingsObserverThread.start();
|
| - mSettingsObserver = new SettingsObserver(
|
| - new Handler(mSettingsObserverThread.getLooper()));
|
| + // Start routing to Bluetooth if there's a connected device.
|
| + // TODO(henrika): the actual routing part is not implemented yet.
|
| + // All we do currently is to detect if BT headset is attached or not.
|
| + initBluetooth();
|
|
|
| mIsInitialized = true;
|
| - if (DEBUG) reportUpdate();
|
| +
|
| + mSettingsObserverThread = new SettingsObserverThread();
|
| + mSettingsObserverThread.start();
|
| + synchronized (mSettingsObserverLock) {
|
| + try {
|
| + mSettingsObserverLock.wait();
|
| + } catch (InterruptedException e) {
|
| + Log.e(TAG, "unregisterHeadsetReceiver exception: " + e.getMessage());
|
| + }
|
| + }
|
| }
|
|
|
| /**
|
| @@ -172,79 +215,33 @@
|
| */
|
| @CalledByNative
|
| public void close() {
|
| - if (DEBUG) logd("close");
|
| if (!mIsInitialized)
|
| return;
|
|
|
| - mSettingsObserverThread.quit();
|
| - try {
|
| - mSettingsObserverThread.join();
|
| - } catch (InterruptedException e) {
|
| - logwtf("HandlerThread.join() exception: " + e.getMessage());
|
| + if (mSettingsObserverThread != null) {
|
| + mSettingsObserverThread = null;
|
| }
|
| - mSettingsObserverThread = null;
|
| - mContentResolver.unregisterContentObserver(mSettingsObserver);
|
| - mSettingsObserver = null;
|
| + if (mSettingsObserver != null) {
|
| + mContentResolver.unregisterContentObserver(mSettingsObserver);
|
| + mSettingsObserver = null;
|
| + }
|
|
|
| unregisterForWiredHeadsetIntentBroadcast();
|
|
|
| + // Restore previously stored audio states.
|
| + setMicrophoneMute(mSavedIsMicrophoneMute);
|
| + setSpeakerphoneOn(mSavedIsSpeakerphoneOn);
|
| +
|
| mIsInitialized = false;
|
| }
|
|
|
| - /**
|
| - * Saves current audio mode and sets audio mode to MODE_IN_COMMUNICATION
|
| - * if input parameter is true. Restores saved audio mode if input parameter
|
| - * is false.
|
| - */
|
| @CalledByNative
|
| - private void setCommunicationAudioModeOn(boolean on) {
|
| - if (DEBUG) logd("setCommunicationAudioModeOn(" + on + ")");
|
| -
|
| - if (on) {
|
| - if (mSavedAudioMode != AudioManager.MODE_INVALID) {
|
| - logwtf("Audio mode has already been set!");
|
| - return;
|
| - }
|
| -
|
| - // Store the current audio mode the first time we try to
|
| - // switch to communication mode.
|
| - try {
|
| - mSavedAudioMode = mAudioManager.getMode();
|
| - } catch (SecurityException e) {
|
| - logwtf("getMode exception: " + e.getMessage());
|
| - logDeviceInfo();
|
| - }
|
| -
|
| - // Store microphone mute state and speakerphone state so it can
|
| - // be restored when closing.
|
| - mSavedIsSpeakerphoneOn = mAudioManager.isSpeakerphoneOn();
|
| - mSavedIsMicrophoneMute = mAudioManager.isMicrophoneMute();
|
| -
|
| - try {
|
| - mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
| - } catch (SecurityException e) {
|
| - logwtf("setMode exception: " + e.getMessage());
|
| - logDeviceInfo();
|
| - }
|
| - } else {
|
| - if (mSavedAudioMode == AudioManager.MODE_INVALID) {
|
| - logwtf("Audio mode has not yet been set!");
|
| - return;
|
| - }
|
| -
|
| - // Restore previously stored audio states.
|
| - setMicrophoneMute(mSavedIsMicrophoneMute);
|
| - setSpeakerphoneOn(mSavedIsSpeakerphoneOn);
|
| -
|
| - // Restore the mode that was used before we switched to
|
| - // communication mode.
|
| - try {
|
| - mAudioManager.setMode(mSavedAudioMode);
|
| - } catch (SecurityException e) {
|
| - logwtf("setMode exception: " + e.getMessage());
|
| - logDeviceInfo();
|
| - }
|
| - mSavedAudioMode = AudioManager.MODE_INVALID;
|
| + public void setMode(int mode) {
|
| + try {
|
| + mAudioManager.setMode(mode);
|
| + } catch (SecurityException e) {
|
| + Log.e(TAG, "setMode exception: " + e.getMessage());
|
| + logDeviceInfo();
|
| }
|
| }
|
|
|
| @@ -253,36 +250,40 @@
|
| *
|
| * @param deviceId Unique device ID (integer converted to string)
|
| * representing the selected device. This string is empty if the so-called
|
| - * default device is requested.
|
| + * default device is selected.
|
| */
|
| @CalledByNative
|
| - private boolean setDevice(String deviceId) {
|
| - if (DEBUG) logd("setDevice: " + deviceId);
|
| - int intDeviceId = deviceId.isEmpty() ?
|
| - DEVICE_DEFAULT : Integer.parseInt(deviceId);
|
| -
|
| - if (intDeviceId == DEVICE_DEFAULT) {
|
| - boolean devices[] = null;
|
| - synchronized (mLock) {
|
| - devices = mAudioDevices.clone();
|
| - mRequestedAudioDevice = DEVICE_DEFAULT;
|
| + public void setDevice(String deviceId) {
|
| + boolean devices[] = null;
|
| + synchronized (mLock) {
|
| + devices = mAudioDevices.clone();
|
| + }
|
| + if (deviceId.isEmpty()) {
|
| + logd("setDevice: default");
|
| + // Use a special selection scheme if the default device is selected.
|
| + // The "most unique" device will be selected; Bluetooth first, then
|
| + // wired headset and last the speaker phone.
|
| + if (devices[DEVICE_BLUETOOTH_HEADSET]) {
|
| + // TODO(henrika): possibly need improvements here if we are
|
| + // in a STATE_BLUETOOTH_TURNING_OFF state.
|
| + setAudioDevice(DEVICE_BLUETOOTH_HEADSET);
|
| + } else if (devices[DEVICE_WIRED_HEADSET]) {
|
| + setAudioDevice(DEVICE_WIRED_HEADSET);
|
| + } else {
|
| + setAudioDevice(DEVICE_SPEAKERPHONE);
|
| }
|
| - int defaultDevice = selectDefaultDevice(devices);
|
| - setAudioDevice(defaultDevice);
|
| - return true;
|
| + } else {
|
| + logd("setDevice: " + deviceId);
|
| + // A non-default device is specified. Verify that it is valid
|
| + // device, and if so, start using it.
|
| + List<Integer> validIds = Arrays.asList(VALID_DEVICES);
|
| + Integer id = Integer.valueOf(deviceId);
|
| + if (validIds.contains(id)) {
|
| + setAudioDevice(id.intValue());
|
| + } else {
|
| + loge("Invalid device ID!");
|
| + }
|
| }
|
| -
|
| - // A non-default device is specified. Verify that it is valid
|
| - // device, and if so, start using it.
|
| - List<Integer> validIds = Arrays.asList(VALID_DEVICES);
|
| - if (!validIds.contains(intDeviceId) || !mAudioDevices[intDeviceId]) {
|
| - return false;
|
| - }
|
| - synchronized (mLock) {
|
| - mRequestedAudioDevice = intDeviceId;
|
| - }
|
| - setAudioDevice(intDeviceId);
|
| - return true;
|
| }
|
|
|
| /**
|
| @@ -292,23 +293,20 @@
|
| */
|
| @CalledByNative
|
| public AudioDeviceName[] getAudioInputDeviceNames() {
|
| - boolean devices[] = null;
|
| synchronized (mLock) {
|
| - devices = mAudioDevices.clone();
|
| - }
|
| - List<String> list = new ArrayList<String>();
|
| - AudioDeviceName[] array =
|
| - new AudioDeviceName[getNumOfAudioDevices(devices)];
|
| - int i = 0;
|
| - for (int id = 0; id < DEVICE_COUNT; ++id) {
|
| - if (devices[id]) {
|
| - array[i] = new AudioDeviceName(id, DEVICE_NAMES[id]);
|
| - list.add(DEVICE_NAMES[id]);
|
| - i++;
|
| + List<String> devices = new ArrayList<String>();
|
| + AudioDeviceName[] array = new AudioDeviceName[getNumOfAudioDevicesWithLock()];
|
| + int i = 0;
|
| + for (int id = 0; id < DEVICE_COUNT; ++id) {
|
| + if (mAudioDevices[id]) {
|
| + array[i] = new AudioDeviceName(id, DEVICE_NAMES[id]);
|
| + devices.add(DEVICE_NAMES[id]);
|
| + i++;
|
| + }
|
| }
|
| + logd("getAudioInputDeviceNames: " + devices);
|
| + return array;
|
| }
|
| - if (DEBUG) logd("getAudioInputDeviceNames: " + list);
|
| - return array;
|
| }
|
|
|
| @CalledByNative
|
| @@ -389,7 +387,7 @@
|
| }
|
|
|
| /** Sets the speaker phone mode. */
|
| - private void setSpeakerphoneOn(boolean on) {
|
| + public void setSpeakerphoneOn(boolean on) {
|
| boolean wasOn = mAudioManager.isSpeakerphoneOn();
|
| if (wasOn == on) {
|
| return;
|
| @@ -398,7 +396,7 @@
|
| }
|
|
|
| /** Sets the microphone mute state. */
|
| - private void setMicrophoneMute(boolean on) {
|
| + public void setMicrophoneMute(boolean on) {
|
| boolean wasMuted = mAudioManager.isMicrophoneMute();
|
| if (wasMuted == on) {
|
| return;
|
| @@ -407,7 +405,7 @@
|
| }
|
|
|
| /** Gets the current microphone mute state. */
|
| - private boolean isMicrophoneMute() {
|
| + public boolean isMicrophoneMute() {
|
| return mAudioManager.isMicrophoneMute();
|
| }
|
|
|
| @@ -426,9 +424,7 @@
|
| IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
|
|
|
| /**
|
| - * Receiver which handles changes in wired headset availability:
|
| - * updates the list of devices;
|
| - * updates the active device if a device selection has been made.
|
| + * Receiver which handles changes in wired headset availablilty.
|
| */
|
| mWiredHeadsetReceiver = new BroadcastReceiver() {
|
| private static final int STATE_UNPLUGGED = 0;
|
| @@ -443,14 +439,13 @@
|
| return;
|
| }
|
| int state = intent.getIntExtra("state", STATE_UNPLUGGED);
|
| - if (DEBUG) {
|
| - int microphone = intent.getIntExtra("microphone", HAS_NO_MIC);
|
| - String name = intent.getStringExtra("name");
|
| - logd("BroadcastReceiver.onReceive: s=" + state
|
| + int microphone = intent.getIntExtra("microphone", HAS_NO_MIC);
|
| + String name = intent.getStringExtra("name");
|
| + logd("==> onReceive: s=" + state
|
| + ", m=" + microphone
|
| + ", n=" + name
|
| + ", sb=" + isInitialStickyBroadcast());
|
| - }
|
| +
|
| switch (state) {
|
| case STATE_UNPLUGGED:
|
| synchronized (mLock) {
|
| @@ -460,30 +455,27 @@
|
| mAudioDevices[DEVICE_EARPIECE] = true;
|
| }
|
| }
|
| + // If wired headset was used before it was unplugged,
|
| + // switch to speaker phone. If it was not in use; just
|
| + // log the change.
|
| + if (mAudioDeviceState == STATE_WIRED_HEADSET_ON) {
|
| + setAudioDevice(DEVICE_SPEAKERPHONE);
|
| + } else {
|
| + reportUpdate();
|
| + }
|
| break;
|
| case STATE_PLUGGED:
|
| synchronized (mLock) {
|
| // Wired headset and earpiece are mutually exclusive.
|
| mAudioDevices[DEVICE_WIRED_HEADSET] = true;
|
| mAudioDevices[DEVICE_EARPIECE] = false;
|
| + setAudioDevice(DEVICE_WIRED_HEADSET);
|
| }
|
| break;
|
| default:
|
| loge("Invalid state!");
|
| break;
|
| }
|
| -
|
| - // Update the existing device selection, but only if a specific
|
| - // device has already been selected explicitly.
|
| - boolean deviceHasBeenRequested = false;
|
| - synchronized (mLock) {
|
| - deviceHasBeenRequested = (mRequestedAudioDevice != DEVICE_INVALID);
|
| - }
|
| - if (deviceHasBeenRequested) {
|
| - updateDeviceActivation();
|
| - } else if (DEBUG) {
|
| - reportUpdate();
|
| - }
|
| }
|
| };
|
|
|
| @@ -500,11 +492,62 @@
|
| }
|
|
|
| /**
|
| + * Check if Bluetooth device is connected, register Bluetooth receiver
|
| + * and start routing to Bluetooth if a device is connected.
|
| + * TODO(henrika): currently only supports the detecion part at startup.
|
| + */
|
| + private void initBluetooth() {
|
| + // Bail out if we don't have the required permission.
|
| + mHasBluetoothPermission = mContext.checkPermission(
|
| + android.Manifest.permission.BLUETOOTH,
|
| + Process.myPid(),
|
| + Process.myUid()) == PackageManager.PERMISSION_GRANTED;
|
| + if (!mHasBluetoothPermission) {
|
| + loge("BLUETOOTH permission is missing!");
|
| + return;
|
| + }
|
| +
|
| + // To get a BluetoothAdapter representing the local Bluetooth adapter,
|
| + // when running on JELLY_BEAN_MR1 (4.2) and below, call the static
|
| + // getDefaultAdapter() method; when running on JELLY_BEAN_MR2 (4.3) and
|
| + // higher, retrieve it through getSystemService(String) with
|
| + // BLUETOOTH_SERVICE.
|
| + // Note: Most methods require the BLUETOOTH permission.
|
| + BluetoothAdapter btAdapter = null;
|
| + if (android.os.Build.VERSION.SDK_INT <=
|
| + android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
| + // Use static method for Android 4.2 and below to get the
|
| + // BluetoothAdapter.
|
| + btAdapter = BluetoothAdapter.getDefaultAdapter();
|
| + } else {
|
| + // Use BluetoothManager to get the BluetoothAdapter for
|
| + // Android 4.3 and above.
|
| + BluetoothManager btManager = (BluetoothManager) mContext.getSystemService(
|
| + Context.BLUETOOTH_SERVICE);
|
| + btAdapter = btManager.getAdapter();
|
| + }
|
| +
|
| + if (btAdapter != null &&
|
| + // android.bluetooth.BluetoothAdapter.getProfileConnectionState
|
| + // requires BLUETOOTH permission.
|
| + android.bluetooth.BluetoothProfile.STATE_CONNECTED ==
|
| + btAdapter.getProfileConnectionState(
|
| + android.bluetooth.BluetoothProfile.HEADSET)) {
|
| + synchronized (mLock) {
|
| + mAudioDevices[DEVICE_BLUETOOTH_HEADSET] = true;
|
| + }
|
| + // TODO(henrika): ensure that we set the active audio
|
| + // device to Bluetooth (not trivial).
|
| + setAudioDevice(DEVICE_BLUETOOTH_HEADSET);
|
| + }
|
| + }
|
| +
|
| + /**
|
| * Changes selection of the currently active audio device.
|
| *
|
| * @param device Specifies the selected audio device.
|
| */
|
| - private void setAudioDevice(int device) {
|
| + public void setAudioDevice(int device) {
|
| switch (device) {
|
| case DEVICE_BLUETOOTH_HEADSET:
|
| // TODO(henrika): add support for turning on an routing to
|
| @@ -513,14 +556,17 @@
|
| break;
|
| case DEVICE_SPEAKERPHONE:
|
| // TODO(henrika): turn off BT if required.
|
| + mAudioDeviceState = STATE_SPEAKERPHONE_ON;
|
| setSpeakerphoneOn(true);
|
| break;
|
| case DEVICE_WIRED_HEADSET:
|
| // TODO(henrika): turn off BT if required.
|
| + mAudioDeviceState = STATE_WIRED_HEADSET_ON;
|
| setSpeakerphoneOn(false);
|
| break;
|
| case DEVICE_EARPIECE:
|
| // TODO(henrika): turn off BT if required.
|
| + mAudioDeviceState = STATE_EARPIECE_ON;
|
| setSpeakerphoneOn(false);
|
| break;
|
| default:
|
| @@ -530,58 +576,11 @@
|
| reportUpdate();
|
| }
|
|
|
| - /**
|
| - * Use a special selection scheme if the default device is selected.
|
| - * The "most unique" device will be selected; Wired headset first,
|
| - * then Bluetooth and last the speaker phone.
|
| - */
|
| - private static int selectDefaultDevice(boolean[] devices) {
|
| - if (devices[DEVICE_WIRED_HEADSET]) {
|
| - return DEVICE_WIRED_HEADSET;
|
| - } else if (devices[DEVICE_BLUETOOTH_HEADSET]) {
|
| - // TODO(henrika): possibly need improvements here if we are
|
| - // in a state where Bluetooth is turning off.
|
| - return DEVICE_BLUETOOTH_HEADSET;
|
| - }
|
| - return DEVICE_SPEAKERPHONE;
|
| - }
|
| -
|
| - /**
|
| - * Updates the active device given the current list of devices and
|
| - * information about if a specific device has been selected or if
|
| - * the default device is selected.
|
| - */
|
| - private void updateDeviceActivation() {
|
| - boolean devices[] = null;
|
| - int requested = DEVICE_INVALID;
|
| - synchronized (mLock) {
|
| - requested = mRequestedAudioDevice;
|
| - devices = mAudioDevices.clone();
|
| - }
|
| - if (requested == DEVICE_INVALID) {
|
| - loge("Unable to activate device since no device is selected!");
|
| - return;
|
| - }
|
| -
|
| - // Update default device if it has been selected explicitly, or
|
| - // the selected device has been removed from the list.
|
| - if (requested == DEVICE_DEFAULT || !devices[requested]) {
|
| - // Get default device given current list and activate the device.
|
| - int defaultDevice = selectDefaultDevice(devices);
|
| - setAudioDevice(defaultDevice);
|
| - } else {
|
| - // Activate the selected device since we know that it exists in
|
| - // the list.
|
| - setAudioDevice(requested);
|
| - }
|
| - }
|
| -
|
| - /** Returns number of available devices */
|
| - private static int getNumOfAudioDevices(boolean[] devices) {
|
| + private int getNumOfAudioDevicesWithLock() {
|
| int count = 0;
|
| for (int i = 0; i < DEVICE_COUNT; ++i) {
|
| - if (devices[i])
|
| - ++count;
|
| + if (mAudioDevices[i])
|
| + count++;
|
| }
|
| return count;
|
| }
|
| @@ -599,10 +598,8 @@
|
| if (mAudioDevices[i])
|
| devices.add(DEVICE_NAMES[i]);
|
| }
|
| - if (DEBUG) {
|
| - logd("reportUpdate: requested=" + mRequestedAudioDevice
|
| - + ", devices=" + devices);
|
| - }
|
| + logd("reportUpdate: state=" + mAudioDeviceState
|
| + + ", devices=" + devices);
|
| }
|
| }
|
|
|
| @@ -622,26 +619,39 @@
|
| Log.e(TAG, msg);
|
| }
|
|
|
| - /** What a Terrible Failure: Reports a condition that should never happen */
|
| - private void logwtf(String msg) {
|
| - Log.wtf(TAG, msg);
|
| - }
|
| -
|
| private class SettingsObserver extends ContentObserver {
|
| - SettingsObserver(Handler handler) {
|
| - super(handler);
|
| + SettingsObserver() {
|
| + super(new Handler());
|
| mContentResolver.registerContentObserver(Settings.System.CONTENT_URI, true, this);
|
| }
|
|
|
| @Override
|
| public void onChange(boolean selfChange) {
|
| - if (DEBUG) logd("SettingsObserver.onChange: " + selfChange);
|
| super.onChange(selfChange);
|
| int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
|
| - if (DEBUG) logd("nativeSetMute: " + (volume == 0));
|
| nativeSetMute(mNativeAudioManagerAndroid, (volume == 0));
|
| }
|
| }
|
|
|
| private native void nativeSetMute(long nativeAudioManagerAndroid, boolean muted);
|
| +
|
| + private class SettingsObserverThread extends Thread {
|
| + SettingsObserverThread() {
|
| + super("SettinsObserver");
|
| + }
|
| +
|
| + @Override
|
| + public void run() {
|
| + // Set this thread up so the handler will work on it.
|
| + Looper.prepare();
|
| +
|
| + synchronized (mSettingsObserverLock) {
|
| + mSettingsObserver = new SettingsObserver();
|
| + mSettingsObserverLock.notify();
|
| + }
|
| +
|
| + // Listen for volume change.
|
| + Looper.loop();
|
| + }
|
| + }
|
| }
|
|
|