am 8dc4c790: am fe8620ac: Merge "Update AudioService to reflect phone state changes with AudioFocus. Phone calls and rings are treated as a new client, with a dedicated client ID that identifies it in the audio focus stack. When it is present in the stack, others clie

Merge commit '8dc4c790e2c278f8f671c728401ee9458d2d74ab' into kraken

* commit '8dc4c790e2c278f8f671c728401ee9458d2d74ab':
  Update AudioService to reflect phone state changes with AudioFocus.
This commit is contained in:
Jean-Michel Trivi
2010-04-20 16:04:08 -07:00
committed by Android Git Automerger

View File

@@ -41,6 +41,8 @@ import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.provider.Settings; import android.provider.Settings;
import android.provider.Settings.System; import android.provider.Settings.System;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.VolumePanel; import android.view.VolumePanel;
@@ -305,6 +307,11 @@ public class AudioService extends IAudioService.Stub {
intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON); intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
context.registerReceiver(mMediaButtonReceiver, intentFilter); context.registerReceiver(mMediaButtonReceiver, intentFilter);
// Register for phone state monitoring
TelephonyManager tmgr = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
} }
private void createAudioSystemThread() { private void createAudioSystemThread() {
@@ -707,7 +714,6 @@ public class AudioService extends IAudioService.Stub {
} }
if (mode != mMode) { if (mode != mMode) {
if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
checkForUndispatchedAudioFocusChange(mMode, mode);
mMode = mode; mMode = mode;
synchronized(mSetModeDeathHandlers) { synchronized(mSetModeDeathHandlers) {
@@ -1903,21 +1909,36 @@ public class AudioService extends IAudioService.Stub {
//========================================================================================== //==========================================================================================
// AudioFocus // AudioFocus
//========================================================================================== //==========================================================================================
/**
* Flag to indicate that the top of the audio focus stack needs to recover focus
* but hasn't been signaled yet.
*/
private boolean mHasUndispatchedAudioFocus = false;
private void checkForUndispatchedAudioFocusChange(int prevMode, int newMode) { /* constant to identify focus stack entry that is used to hold the focus while the phone
// when exiting a call * is ringing or during a call
if ((prevMode == AudioSystem.MODE_IN_CALL) && (newMode != AudioSystem.MODE_IN_CALL)) { */
// check for undispatched remote control focus gain private final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
if (mHasUndispatchedAudioFocus) {
notifyTopOfAudioFocusStack(); private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING) {
//Log.v(TAG, " CALL_STATE_RINGING");
int ringVolume = AudioService.this.getStreamVolume(AudioManager.STREAM_RING);
if (ringVolume > 0) {
requestAudioFocus(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
null, null /* both allowed to be null only for this clientId */,
IN_VOICE_COMM_FOCUS_ID /*clientId*/);
}
} else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
//Log.v(TAG, " CALL_STATE_OFFHOOK");
requestAudioFocus(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
null, null /* both allowed to be null only for this clientId */,
IN_VOICE_COMM_FOCUS_ID /*clientId*/);
} else if (state == TelephonyManager.CALL_STATE_IDLE) {
//Log.v(TAG, " CALL_STATE_IDLE");
abandonAudioFocus(null, IN_VOICE_COMM_FOCUS_ID);
} }
} }
} };
private void notifyTopOfAudioFocusStack() { private void notifyTopOfAudioFocusStack() {
// notify the top of the stack it gained focus // notify the top of the stack it gained focus
@@ -1926,13 +1947,10 @@ public class AudioService extends IAudioService.Stub {
try { try {
mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
mHasUndispatchedAudioFocus = false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
e.printStackTrace(); e.printStackTrace();
} }
} else {
mHasUndispatchedAudioFocus = true;
} }
} }
} }
@@ -1966,7 +1984,7 @@ public class AudioService extends IAudioService.Stub {
* Display in the log the current entries in the audio focus stack * Display in the log the current entries in the audio focus stack
*/ */
private void dumpFocusStack(PrintWriter pw) { private void dumpFocusStack(PrintWriter pw) {
pw.println("Audio Focus stack entries:"); pw.println("\nAudio Focus stack entries:");
synchronized(mFocusStack) { synchronized(mFocusStack) {
Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) { while(stackIterator.hasNext()) {
@@ -2038,9 +2056,9 @@ public class AudioService extends IAudioService.Stub {
* Returns true if the system is in a state where the focus can be reevaluated, false otherwise. * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
*/ */
private boolean canReassignAudioFocus() { private boolean canReassignAudioFocus() {
// focus requests are rejected during a phone call // focus requests are rejected during a phone call or when the phone is ringing
if (getMode() == AudioSystem.MODE_IN_CALL) { // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
Log.i(TAG, " AudioFocus can't be reassigned during a call, exiting"); if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
return false; return false;
} }
return true; return true;
@@ -2077,7 +2095,9 @@ public class AudioService extends IAudioService.Stub {
// the main stream type for the audio focus request is currently not used. It may // the main stream type for the audio focus request is currently not used. It may
// potentially be used to handle multiple stream type-dependent audio focuses. // potentially be used to handle multiple stream type-dependent audio focuses.
if ((cb == null) || !cb.pingBinder()) { // we need a valid binder callback for clients other than the AudioService's phone
// state listener
if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId) && ((cb == null) || !cb.pingBinder())) {
Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting"); Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED; return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
} }
@@ -2119,14 +2139,17 @@ public class AudioService extends IAudioService.Stub {
}//synchronized(mFocusStack) }//synchronized(mFocusStack)
// handle the potential premature death of the new holder of the focus // handle the potential premature death of the new holder of the focus
// (premature death == death before abandoning focus) // (premature death == death before abandoning focus) for a client which is not the
// Register for client death notification // AudioService's phone state listener
AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
try { // Register for client death notification
cb.linkToDeath(afdh, 0); AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
} catch (RemoteException e) { try {
// client has already died! cb.linkToDeath(afdh, 0);
Log.w(TAG, " AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); } catch (RemoteException e) {
// client has already died!
Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
}
} }
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
@@ -2212,7 +2235,7 @@ public class AudioService extends IAudioService.Stub {
* Display in the log the current entries in the remote control focus stack * Display in the log the current entries in the remote control focus stack
*/ */
private void dumpRCStack(PrintWriter pw) { private void dumpRCStack(PrintWriter pw) {
pw.println("Remote Control stack entries:"); pw.println("\nRemote Control stack entries:");
synchronized(mRCStack) { synchronized(mRCStack) {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) { while(stackIterator.hasNext()) {