Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4bccb6d authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

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 clients cannot request audio focus
(request is denied).
Because the phone state is now mostly handled like a new client,
there is no need monitor mode changes and to keep track of
undispatched focus changes, as those will delayed focus gains
will now automatically happen at the end of the call when the
phone client is removed from the focus stack.

Change-Id: I11ff73b015ab93f07040755fd8ee75c8d675e025
parent 25dc5f30
Loading
Loading
Loading
Loading
+52 −29
Original line number Original line Diff line number Diff line
@@ -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
    /* constant to identify focus stack entry that is used to hold the focus while the phone
     * but hasn't been signaled yet.
     * is ringing or during a call
     */
     */
    private boolean mHasUndispatchedAudioFocus = false;
    private final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";


    private void checkForUndispatchedAudioFocusChange(int prevMode, int newMode) {
    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
        // when exiting a call
        @Override
        if ((prevMode == AudioSystem.MODE_IN_CALL) && (newMode != AudioSystem.MODE_IN_CALL)) {
        public void onCallStateChanged(int state, String incomingNumber) {
            // check for undispatched remote control focus gain
            if (state == TelephonyManager.CALL_STATE_RINGING) {
            if (mHasUndispatchedAudioFocus) {
                //Log.v(TAG, " CALL_STATE_RINGING");
                notifyTopOfAudioFocusStack();
                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,7 +2139,9 @@ 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
        // AudioService's phone state listener
        if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
            // Register for client death notification
            // Register for client death notification
            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
            try {
            try {
@@ -2128,6 +2150,7 @@ public class AudioService extends IAudioService.Stub {
                // client has already died!
                // client has already died!
                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
                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()) {