Chromium Code Reviews| 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 c61b86af70acdf248839fb2733e1043ad6b4d116..c3d102d49cb331efa07d426245c20dfcc0a50ff2 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; |
| @@ -19,8 +17,7 @@ import android.media.AudioRecord; |
| import android.media.AudioTrack; |
| 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; |
| @@ -36,7 +33,7 @@ class AudioManagerAndroid { |
| private static final String TAG = "AudioManagerAndroid"; |
| // Set to true to enable debug logs. Always check in as false. |
| - private static final boolean DEBUG = false; |
| + private static final boolean DEBUG = true; |
|
bulach
2013/12/13 13:49:49
make sure you change it back :)
henrika (OOO until Aug 14)
2013/12/13 14:58:42
Done.
|
| /** Simple container for device information. */ |
| private static class AudioDeviceName { |
| @@ -55,7 +52,8 @@ class AudioManagerAndroid { |
| private String name() { return mName; } |
| } |
| - // Supported audio device types. |
| + // Supported audio device types. |
|
bulach
2013/12/13 13:49:49
nit: unindent
henrika (OOO until Aug 14)
2013/12/13 14:58:42
Done.
|
| + 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; |
| @@ -82,24 +80,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. |
| @@ -111,12 +91,15 @@ 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. |
| @@ -127,9 +110,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; |
| @@ -156,56 +138,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(); |
| } |
| /** |
| @@ -214,33 +171,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(); |
| + public 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; |
| } |
| } |
| @@ -252,37 +255,31 @@ class AudioManagerAndroid { |
| * default device is selected. |
| */ |
| @CalledByNative |
| - public void setDevice(String deviceId) { |
| + boolean setDevice(String deviceId) { |
|
bulach
2013/12/13 13:49:49
nit: maybe private?
henrika (OOO until Aug 14)
2013/12/13 14:58:42
Done. Did same for all methods in this class.
|
| 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); |
| + if (DEBUG) logd("setDevice: default"); |
| + int defaultDevice = selectDefaultDevice(devices); |
| + setAudioDevice(defaultDevice); |
| + mRequestedAudioDevice = DEVICE_DEFAULT; |
|
bulach
2013/12/13 13:49:49
nit: needs to be protected by mLock? more below, i
henrika (OOO until Aug 14)
2013/12/13 14:58:42
Done.
|
| + return true; |
| + } else if (isNumeric(deviceId)) { |
| + if (DEBUG) 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)) { |
| + if (validIds.contains(id) && mAudioDevices[id.intValue()]) { |
| + mRequestedAudioDevice = id.intValue(); |
|
bulach
2013/12/13 13:49:49
nit: mLock?
henrika (OOO until Aug 14)
2013/12/13 14:58:42
Done.
|
| setAudioDevice(id.intValue()); |
| - } else { |
| - loge("Invalid device ID!"); |
| + return true; |
| } |
| } |
| + loge("Invalid device ID: " + deviceId); |
| + return false; |
| } |
| /** |
| @@ -292,20 +289,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 |
| @@ -412,7 +412,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; |
| @@ -429,11 +431,12 @@ class AudioManagerAndroid { |
| 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) { |
| + logd("BroadcastReceiver.onReceive: s=" + state |
| + ", m=" + microphone |
| + ", n=" + name |
| + ", sb=" + isInitialStickyBroadcast()); |
| - |
| + } |
| switch (state) { |
| case STATE_UNPLUGGED: |
| synchronized (mLock) { |
| @@ -443,27 +446,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) { |
|
bulach
2013/12/13 13:49:49
as above, the comment on mLock says it only protec
henrika (OOO until Aug 14)
2013/12/13 14:58:42
Done.
|
| + deviceHasBeenRequested = (mRequestedAudioDevice != DEVICE_INVALID); |
| + } |
| + if (deviceHasBeenRequested) { |
| + updateDeviceActivation(); |
| + } else if (DEBUG) { |
| + reportUpdate(); |
| + } |
| } |
| }; |
| @@ -480,57 +486,6 @@ 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. |
| @@ -544,17 +499,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: |
| @@ -564,15 +516,71 @@ 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[mRequestedAudioDevice]) { |
|
bulach
2013/12/13 13:49:49
nit: s/mRequestedAudioDevice/requested/, otherwise
henrika (OOO until Aug 14)
2013/12/13 14:58:42
Thanks!
|
| + // 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; |
| } |
| + private static boolean isNumeric(String str) { |
| + for (char c : str.toCharArray()) { |
| + if (!Character.isDigit(c)) { |
| + return false; |
| + } |
| + } |
| + return true; |
| + } |
| + |
| /** |
| * For now, just log the state change but the idea is that we should |
| * notify a registered state change listener (if any) that there has |
| @@ -586,8 +594,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); |
| + } |
| } |
| } |
| @@ -607,39 +617,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(); |
| - } |
| - } |
| } |