Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Unified Diff: media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java

Issue 117073002: Reland "Refactor audio manager for Android to avoid heavy tasks at startup" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/audio/android/audio_manager_android.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
- }
- }
}
« no previous file with comments | « media/audio/android/audio_manager_android.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698