| Index: media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
|
| diff --git a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
|
| index afaa0358ec184f956b2616f0037b33f699454f1e..15d7aef6959d78bcd0bd527a16ecbfe7f3051694 100644
|
| --- a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
|
| +++ b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
|
| @@ -4,8 +4,6 @@
|
|
|
| package org.chromium.media;
|
|
|
| -import android.bluetooth.BluetoothAdapter;
|
| -import android.bluetooth.BluetoothManager;
|
| import android.content.BroadcastReceiver;
|
| import android.content.ContentResolver;
|
| import android.content.Context;
|
| @@ -20,8 +18,7 @@ import android.media.AudioTrack;
|
| import android.media.audiofx.AcousticEchoCanceler;
|
| import android.os.Build;
|
| import android.os.Handler;
|
| -import android.os.Looper;
|
| -import android.os.Process;
|
| +import android.os.HandlerThread;
|
| import android.provider.Settings;
|
| import android.util.Log;
|
|
|
| @@ -57,6 +54,7 @@ class AudioManagerAndroid {
|
| }
|
|
|
| // 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;
|
| @@ -83,24 +81,6 @@ class AudioManagerAndroid {
|
| 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.
|
| @@ -112,15 +92,18 @@ class AudioManagerAndroid {
|
| private final Context mContext;
|
| private final long mNativeAudioManagerAndroid;
|
|
|
| - private boolean mHasBluetoothPermission = false;
|
| + private int mSavedAudioMode = AudioManager.MODE_INVALID;
|
| +
|
| private boolean mIsInitialized = false;
|
| private boolean mSavedIsSpeakerphoneOn;
|
| private boolean mSavedIsMicrophoneMute;
|
|
|
| - private Integer mAudioDeviceState = STATE_NO_DEVICE_SELECTED;
|
| + // Id of the requested audio device. Can only be modified by
|
| + // call to setDevice().
|
| + private int mRequestedAudioDevice = DEVICE_INVALID;
|
|
|
| - // Lock to protect |mAudioDevices| which can be accessed from the main
|
| - // thread and the audio manager thread.
|
| + // Lock to protect |mAudioDevices| and |mRequestedAudioDevice| 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.
|
| @@ -128,9 +111,8 @@ class AudioManagerAndroid {
|
|
|
| private final ContentResolver mContentResolver;
|
| private SettingsObserver mSettingsObserver = null;
|
| - private SettingsObserverThread mSettingsObserverThread = null;
|
| + private HandlerThread mSettingsObserverThread = null;
|
| private int mCurrentVolume;
|
| - private final Object mSettingsObserverLock = new Object();
|
|
|
| // Broadcast receiver for wired headset intent broadcasts.
|
| private BroadcastReceiver mWiredHeadsetReceiver;
|
| @@ -157,56 +139,31 @@ class AudioManagerAndroid {
|
| */
|
| @CalledByNative
|
| public void init() {
|
| + if (DEBUG) logd("init");
|
| if (mIsInitialized)
|
| return;
|
|
|
| - synchronized (mLock) {
|
| - for (int i = 0; i < DEVICE_COUNT; ++i) {
|
| - mAudioDevices[i] = false;
|
| - }
|
| + 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.
|
| - synchronized (mLock) {
|
| - if (hasEarpiece()) {
|
| - mAudioDevices[DEVICE_EARPIECE] = true;
|
| - }
|
| - mAudioDevices[DEVICE_SPEAKERPHONE] = true;
|
| + if (hasEarpiece()) {
|
| + mAudioDevices[DEVICE_EARPIECE] = 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();
|
|
|
| - // 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();
|
| + mSettingsObserverThread = new HandlerThread("SettingsObserver");
|
| + mSettingsObserverThread.start();
|
| + mSettingsObserver = new SettingsObserver(
|
| + new Handler(mSettingsObserverThread.getLooper()));
|
|
|
| mIsInitialized = true;
|
| -
|
| - mSettingsObserverThread = new SettingsObserverThread();
|
| - mSettingsObserverThread.start();
|
| - synchronized (mSettingsObserverLock) {
|
| - try {
|
| - mSettingsObserverLock.wait();
|
| - } catch (InterruptedException e) {
|
| - Log.e(TAG, "unregisterHeadsetReceiver exception: " + e.getMessage());
|
| - }
|
| - }
|
| + if (DEBUG) reportUpdate();
|
| }
|
|
|
| /**
|
| @@ -215,33 +172,79 @@ class AudioManagerAndroid {
|
| */
|
| @CalledByNative
|
| public void close() {
|
| + if (DEBUG) logd("close");
|
| if (!mIsInitialized)
|
| return;
|
|
|
| - if (mSettingsObserverThread != null) {
|
| - mSettingsObserverThread = null;
|
| - }
|
| - if (mSettingsObserver != null) {
|
| - mContentResolver.unregisterContentObserver(mSettingsObserver);
|
| - mSettingsObserver = null;
|
| + mSettingsObserverThread.quit();
|
| + try {
|
| + mSettingsObserverThread.join();
|
| + } catch (InterruptedException e) {
|
| + logwtf("HandlerThread.join() exception: " + e.getMessage());
|
| }
|
| + mSettingsObserverThread = 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
|
| - public void setMode(int mode) {
|
| - try {
|
| - mAudioManager.setMode(mode);
|
| - } catch (SecurityException e) {
|
| - Log.e(TAG, "setMode exception: " + e.getMessage());
|
| - logDeviceInfo();
|
| + 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;
|
| }
|
| }
|
|
|
| @@ -250,40 +253,36 @@ class AudioManagerAndroid {
|
| *
|
| * @param deviceId Unique device ID (integer converted to string)
|
| * representing the selected device. This string is empty if the so-called
|
| - * default device is selected.
|
| + * default device is requested.
|
| */
|
| @CalledByNative
|
| - 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);
|
| - }
|
| - } 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!");
|
| + 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;
|
| }
|
| + int defaultDevice = selectDefaultDevice(devices);
|
| + setAudioDevice(defaultDevice);
|
| + return true;
|
| }
|
| +
|
| + // 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;
|
| }
|
|
|
| /**
|
| @@ -293,20 +292,23 @@ class AudioManagerAndroid {
|
| */
|
| @CalledByNative
|
| public AudioDeviceName[] getAudioInputDeviceNames() {
|
| + boolean devices[] = null;
|
| synchronized (mLock) {
|
| - 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++;
|
| - }
|
| + 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++;
|
| }
|
| - logd("getAudioInputDeviceNames: " + devices);
|
| - return array;
|
| }
|
| + if (DEBUG) logd("getAudioInputDeviceNames: " + list);
|
| + return array;
|
| }
|
|
|
| @CalledByNative
|
| @@ -387,7 +389,7 @@ class AudioManagerAndroid {
|
| }
|
|
|
| /** Sets the speaker phone mode. */
|
| - public void setSpeakerphoneOn(boolean on) {
|
| + private void setSpeakerphoneOn(boolean on) {
|
| boolean wasOn = mAudioManager.isSpeakerphoneOn();
|
| if (wasOn == on) {
|
| return;
|
| @@ -396,7 +398,7 @@ class AudioManagerAndroid {
|
| }
|
|
|
| /** Sets the microphone mute state. */
|
| - public void setMicrophoneMute(boolean on) {
|
| + private void setMicrophoneMute(boolean on) {
|
| boolean wasMuted = mAudioManager.isMicrophoneMute();
|
| if (wasMuted == on) {
|
| return;
|
| @@ -405,7 +407,7 @@ class AudioManagerAndroid {
|
| }
|
|
|
| /** Gets the current microphone mute state. */
|
| - public boolean isMicrophoneMute() {
|
| + private boolean isMicrophoneMute() {
|
| return mAudioManager.isMicrophoneMute();
|
| }
|
|
|
| @@ -424,7 +426,9 @@ class AudioManagerAndroid {
|
| IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
|
|
|
| /**
|
| - * Receiver which handles changes in wired headset availablilty.
|
| + * Receiver which handles changes in wired headset availability:
|
| + * updates the list of devices;
|
| + * updates the active device if a device selection has been made.
|
| */
|
| mWiredHeadsetReceiver = new BroadcastReceiver() {
|
| private static final int STATE_UNPLUGGED = 0;
|
| @@ -439,13 +443,14 @@ class AudioManagerAndroid {
|
| return;
|
| }
|
| int state = intent.getIntExtra("state", STATE_UNPLUGGED);
|
| - int microphone = intent.getIntExtra("microphone", HAS_NO_MIC);
|
| - String name = intent.getStringExtra("name");
|
| - logd("==> onReceive: s=" + state
|
| + if (DEBUG) {
|
| + int microphone = intent.getIntExtra("microphone", HAS_NO_MIC);
|
| + String name = intent.getStringExtra("name");
|
| + logd("BroadcastReceiver.onReceive: s=" + state
|
| + ", m=" + microphone
|
| + ", n=" + name
|
| + ", sb=" + isInitialStickyBroadcast());
|
| -
|
| + }
|
| switch (state) {
|
| case STATE_UNPLUGGED:
|
| synchronized (mLock) {
|
| @@ -455,27 +460,30 @@ class AudioManagerAndroid {
|
| 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();
|
| + }
|
| }
|
| };
|
|
|
| @@ -492,62 +500,11 @@ class AudioManagerAndroid {
|
| }
|
|
|
| /**
|
| - * 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.
|
| */
|
| - public void setAudioDevice(int device) {
|
| + private void setAudioDevice(int device) {
|
| switch (device) {
|
| case DEVICE_BLUETOOTH_HEADSET:
|
| // TODO(henrika): add support for turning on an routing to
|
| @@ -556,17 +513,14 @@ class AudioManagerAndroid {
|
| 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:
|
| @@ -576,11 +530,58 @@ class AudioManagerAndroid {
|
| reportUpdate();
|
| }
|
|
|
| - private int getNumOfAudioDevicesWithLock() {
|
| + /**
|
| + * 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) {
|
| int count = 0;
|
| for (int i = 0; i < DEVICE_COUNT; ++i) {
|
| - if (mAudioDevices[i])
|
| - count++;
|
| + if (devices[i])
|
| + ++count;
|
| }
|
| return count;
|
| }
|
| @@ -598,8 +599,10 @@ class AudioManagerAndroid {
|
| if (mAudioDevices[i])
|
| devices.add(DEVICE_NAMES[i]);
|
| }
|
| - logd("reportUpdate: state=" + mAudioDeviceState
|
| - + ", devices=" + devices);
|
| + if (DEBUG) {
|
| + logd("reportUpdate: requested=" + mRequestedAudioDevice
|
| + + ", devices=" + devices);
|
| + }
|
| }
|
| }
|
|
|
| @@ -619,39 +622,26 @@ class AudioManagerAndroid {
|
| 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() {
|
| - super(new Handler());
|
| + SettingsObserver(Handler handler) {
|
| + super(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();
|
| - }
|
| - }
|
| }
|
|
|