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

Commit 947b2df2 authored by Benson Li's avatar Benson Li Committed by Android Build Coastguard Worker
Browse files

Revert "Revert "Revert "Ensure MediaSession is ONLY made active when routed to wired headset."""

This reverts commit 55793f0c.

Reason for revert: b/283204143
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4e5131e61cebe82fcf03d203649a8848c25c57ce)
Merged-In: I6c33060823b8d7d4353cdb8fee98e3d31be93ac5
Change-Id: I6c33060823b8d7d4353cdb8fee98e3d31be93ac5
parent 70a44d35
Loading
Loading
Loading
Loading
+21 −48
Original line number Diff line number Diff line
@@ -23,16 +23,11 @@ import android.media.session.MediaSession;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.telecom.CallAudioState;
import android.telecom.CallEndpoint;
import android.telecom.Log;
import android.util.ArraySet;
import android.view.KeyEvent;

import com.android.internal.annotations.VisibleForTesting;

import java.util.Set;

/**
 * Static class to handle listening to the headset media buttons.
 */
@@ -154,10 +149,8 @@ public class HeadsetMediaButton extends CallsManagerListenerBase {
    private final Context mContext;
    private final CallsManager mCallsManager;
    private final TelecomSystem.SyncRoot mLock;
    private final Set<Call> mCalls = new ArraySet<>();
    private MediaSessionAdapter mSession;
    private KeyEvent mLastHookEvent;
    private @CallEndpoint.EndpointType int mCurrentEndpointType;

    /**
     * Constructor used for testing purposes to initialize a {@link HeadsetMediaButton} with a
@@ -219,7 +212,7 @@ public class HeadsetMediaButton extends CallsManagerListenerBase {
            return mCallsManager.onMediaButton(LONG_PRESS);
        } else if (event.getAction() == KeyEvent.ACTION_UP) {
            // We should not judge SHORT_PRESS by ACTION_UP event repeatCount, because it always
            // returns 0.
            // return 0.
            // Actually ACTION_DOWN event repeatCount only increases when LONG_PRESS performed.
            if (mLastHookEvent != null && mLastHookEvent.getRepeatCount() == 0) {
                return mCallsManager.onMediaButton(SHORT_PRESS);
@@ -233,70 +226,50 @@ public class HeadsetMediaButton extends CallsManagerListenerBase {
        return true;
    }

    @Override
    public void onCallEndpointChanged(CallEndpoint callEndpoint) {
        mCurrentEndpointType = callEndpoint.getEndpointType();
        Log.i(this, "onCallEndpointChanged: endPoint=%s", callEndpoint);
        maybeChangeSessionState();
    }

    /** ${inheritDoc} */
    @Override
    public void onCallAdded(Call call) {
        handleCallAddition(call);
        if (call.isExternalCall()) {
            return;
        }

    /**
     * Triggers session activation due to call addition.
     */
    private void handleCallAddition(Call call) {
        mCalls.add(call);
        maybeChangeSessionState();
        handleCallAddition();
    }

    /**
     * Based on whether there are tracked calls and the audio is routed to a wired headset,
     * potentially activate or deactive the media session.
     * Triggers session activation due to call addition.
     */
    private void maybeChangeSessionState() {
        boolean hasNonExternalCalls = !mCalls.isEmpty()
                && mCalls.stream().anyMatch(c -> !c.isExternalCall());
        if (hasNonExternalCalls && mCurrentEndpointType == CallEndpoint.TYPE_WIRED_HEADSET) {
            Log.i(this, "maybeChangeSessionState: hasCalls=%b, currentEndpointType=%s, ACTIVATE",
                    hasNonExternalCalls, CallEndpoint.endpointTypeToString(mCurrentEndpointType));
    private void handleCallAddition() {
        mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 1, 0).sendToTarget();
        } else {
            Log.i(this, "maybeChangeSessionState: hasCalls=%b, currentEndpointType=%s, DEACTIVATE",
                    hasNonExternalCalls, CallEndpoint.endpointTypeToString(mCurrentEndpointType));
            mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 0, 0).sendToTarget();
        }
    }

    /** ${inheritDoc} */
    @Override
    public void onCallRemoved(Call call) {
        handleCallRemoval(call);
        if (call.isExternalCall()) {
            return;
        }
        handleCallRemoval();
    }

    /**
     * Triggers session deactivation due to call removal.
     */
    private void handleCallRemoval(Call call) {
        // If we were tracking the call, potentially change session state.
        if (mCalls.remove(call)) {
            if (mCalls.isEmpty()) {
                // When there are no calls, don't cache that we previously had a wired headset
                // connected; we'll be updated on the next call.
                mCurrentEndpointType = CallEndpoint.TYPE_UNKNOWN;
            }
            maybeChangeSessionState();
    private void handleCallRemoval() {
        if (!mCallsManager.hasAnyCalls()) {
            mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 0, 0).sendToTarget();
        }
    }

    /** ${inheritDoc} */
    @Override
    public void onExternalCallChanged(Call call, boolean isExternalCall) {
        maybeChangeSessionState();
        // Note: We don't use the onCallAdded/onCallRemoved methods here since they do checks to see
        // if the call is external or not and would skip the session activation/deactivation.
        if (isExternalCall) {
            handleCallRemoval();
        } else {
            handleCallAddition();
        }
    }

    @VisibleForTesting
+3 −90
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.server.telecom.tests;

import android.content.Intent;
import android.media.session.MediaSession;
import android.telecom.CallEndpoint;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.KeyEvent;
@@ -81,7 +80,7 @@ public class HeadsetMediaButtonTest extends TelecomTestCase {
    }

    /**
     * Nominal case; just add a call and remove it; this happens when the audio state is earpiece.
     * Nominal case; just add a call and remove it.
     */
    @SmallTest
    @Test
@@ -91,95 +90,14 @@ public class HeadsetMediaButtonTest extends TelecomTestCase {
        when(mMockCallsManager.hasAnyCalls()).thenReturn(true);
        mHeadsetMediaButton.onCallAdded(regularCall);
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, never()).setActive(eq(true));

        // Report that the endpoint is earpiece and other routes that don't matter
        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Earpiece", CallEndpoint.TYPE_EARPIECE));
        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Speaker", CallEndpoint.TYPE_SPEAKER));
        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("BT", CallEndpoint.TYPE_BLUETOOTH));
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, never()).setActive(eq(true));

        // ... and thus we see how the original code isn't amenable to tests.
        when(mMediaSessionAdapter.isActive()).thenReturn(false);

        // Still should not have done anything; we never hit wired headset
        mHeadsetMediaButton.onCallRemoved(regularCall);
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, never()).setActive(eq(false));
    }

    /**
     * Call is added and then routed to headset after call start
     */
    @SmallTest
    @Test
    public void testAddCallThenRouteToHeadset() {
        Call regularCall = getRegularCall();

        mHeadsetMediaButton.onCallAdded(regularCall);
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, never()).setActive(eq(true));

        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Wired Headset", CallEndpoint.TYPE_WIRED_HEADSET));
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter).setActive(eq(true));

        // ... and thus we see how the original code isn't amenable to tests.
        when(mMediaSessionAdapter.isActive()).thenReturn(true);

        // Remove the one call; we should release the session.
        when(mMockCallsManager.hasAnyCalls()).thenReturn(false);
        mHeadsetMediaButton.onCallRemoved(regularCall);
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter).setActive(eq(false));
        when(mMediaSessionAdapter.isActive()).thenReturn(false);

        // Add a new call; make sure we go active once more.
        mHeadsetMediaButton.onCallAdded(regularCall);
        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Wired Headset", CallEndpoint.TYPE_WIRED_HEADSET));
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, times(2)).setActive(eq(true));
    }

    /**
     * Call is added and then routed to headset after call start
     */
    @SmallTest
    @Test
    public void testAddCallThenRouteToHeadsetAndBack() {
        Call regularCall = getRegularCall();

        when(mMockCallsManager.hasAnyCalls()).thenReturn(true);
        mHeadsetMediaButton.onCallAdded(regularCall);
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, never()).setActive(eq(true));

        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Wired Headset", CallEndpoint.TYPE_WIRED_HEADSET));
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter).setActive(eq(true));

        // ... and thus we see how the original code isn't amenable to tests.
        when(mMediaSessionAdapter.isActive()).thenReturn(true);

        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Earpiece", CallEndpoint.TYPE_EARPIECE));
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter).setActive(eq(false));
        when(mMediaSessionAdapter.isActive()).thenReturn(false);

        // Remove the one call; we should not release again.
        mHeadsetMediaButton.onCallRemoved(regularCall);
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        // Remember, mockito counts total invocations; we should have went active once and then
        // inactive again when we hit earpiece.
        verify(mMediaSessionAdapter, times(1)).setActive(eq(true));
        verify(mMediaSessionAdapter, times(1)).setActive(eq(false));
    }

    /**
@@ -193,8 +111,6 @@ public class HeadsetMediaButtonTest extends TelecomTestCase {
        // Start with a regular old call.
        when(mMockCallsManager.hasAnyCalls()).thenReturn(true);
        mHeadsetMediaButton.onCallAdded(regularCall);
        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Wired Headset", CallEndpoint.TYPE_WIRED_HEADSET));
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter).setActive(eq(true));
        when(mMediaSessionAdapter.isActive()).thenReturn(true);
@@ -206,7 +122,6 @@ public class HeadsetMediaButtonTest extends TelecomTestCase {
        // Expect to set session inactive.
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter).setActive(eq(false));
        when(mMediaSessionAdapter.isActive()).thenReturn(false);

        // For good measure lets make it non-external again.
        when(regularCall.isExternalCall()).thenReturn(false);
@@ -214,7 +129,7 @@ public class HeadsetMediaButtonTest extends TelecomTestCase {
        mHeadsetMediaButton.onExternalCallChanged(regularCall, false);
        // Expect to set session active.
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, times(2)).setActive(eq(true));
        verify(mMediaSessionAdapter).setActive(eq(true));
    }

    @MediumTest
@@ -224,8 +139,6 @@ public class HeadsetMediaButtonTest extends TelecomTestCase {
        when(externalCall.isExternalCall()).thenReturn(true);

        mHeadsetMediaButton.onCallAdded(externalCall);
        mHeadsetMediaButton.onCallEndpointChanged(
                new CallEndpoint("Wired Headset", CallEndpoint.TYPE_WIRED_HEADSET));
        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
        verify(mMediaSessionAdapter, never()).setActive(eq(true));