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(); |
- } |
- } |
} |