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

Commit d2280477 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Handle video capability changes mid-call.

Add phone account changed listener method in phone account registrar which
will trigger an update of video capabilities for ongoing calls.  This is
to ensure that if the device becomes video capable (or not) during calls
that the caches "is video capable for phone account" indicator for the
calls are updated appropriately and that the current connection capabilities
is updated.

Test: Added new unit tests
Bug: 79185391
Change-Id: If43af6889ff07aad6fd08571a29352d882ffd675
parent 168fe2f0
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
@@ -1250,6 +1250,23 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        return mIsVideoCallingSupportedByPhoneAccount;
    }

    /**
     * Sets whether video calling is supported by the current phone account. Since video support
     * can change during a call, this method facilitates updating call video state.
     * @param isVideoCallingSupported Sets whether video calling is supported.
     */
    public void setVideoCallingSupportedByPhoneAccount(boolean isVideoCallingSupported) {
        if (mIsVideoCallingSupportedByPhoneAccount == isVideoCallingSupported) {
            return;
        }
        Log.i(this, "setVideoCallingSupportedByPhoneAccount: isSupp=%b", isVideoCallingSupported);
        mIsVideoCallingSupportedByPhoneAccount = isVideoCallingSupported;

        // Force an update of the connection capabilities so that the dialer is informed of the new
        // video capabilities based on the phone account's support for video.
        setConnectionCapabilities(getConnectionCapabilities(), true /* force */);
    }

    /**
     * @return {@code true} if the {@link Call} locally supports video.
     */
@@ -1363,8 +1380,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        }
        PhoneAccount phoneAccount =
                phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle);
        mIsVideoCallingSupportedByPhoneAccount = phoneAccount != null && phoneAccount.hasCapabilities(
                    PhoneAccount.CAPABILITY_VIDEO_CALLING);
        mIsVideoCallingSupportedByPhoneAccount = phoneAccount != null &&
                phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING);

        if (!mIsVideoCallingSupportedByPhoneAccount && VideoProfile.isVideo(getVideoState())) {
            // The PhoneAccount for the Call was set to one which does not support video calling,
@@ -1455,7 +1472,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        mConnectElapsedTimeMillis = connectElapsedTimeMillis;
    }

    int getConnectionCapabilities() {
    public int getConnectionCapabilities() {
        return mConnectionCapabilities;
    }

@@ -1463,7 +1480,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        return mConnectionProperties;
    }

    void setConnectionCapabilities(int connectionCapabilities) {
    public void setConnectionCapabilities(int connectionCapabilities) {
        setConnectionCapabilities(connectionCapabilities, false /* forceUpdate */);
    }

+30 −0
Original line number Diff line number Diff line
@@ -340,6 +340,12 @@ public class CallsManager extends Call.ListenerBase
                                               PhoneAccountHandle handle) {
            broadcastUnregisterIntent(handle);
        }

        @Override
        public void onPhoneAccountChanged(PhoneAccountRegistrar registrar,
                PhoneAccount phoneAccount) {
            handlePhoneAccountChanged(registrar, phoneAccount);
        }
    };

    /**
@@ -924,6 +930,11 @@ public class CallsManager extends Call.ListenerBase
        return mEmergencyCallHelper;
    }

    @VisibleForTesting
    public PhoneAccountRegistrar.Listener getPhoneAccountListener() {
        return mPhoneAccountListener;
    }

    @VisibleForTesting
    public boolean hasEmergencyCall() {
        for (Call call : mCalls) {
@@ -4461,4 +4472,23 @@ public class CallsManager extends Call.ListenerBase
        errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT);
    }

    /**
     * Handles changes to a {@link PhoneAccount}.
     *
     * Checks for changes to video calling availability and updates whether calls for that phone
     * account are video capable.
     *
     * @param registrar The {@link PhoneAccountRegistrar} originating the change.
     * @param phoneAccount The {@link PhoneAccount} which changed.
     */
    private void handlePhoneAccountChanged(PhoneAccountRegistrar registrar,
            PhoneAccount phoneAccount) {
        Log.i(this, "handlePhoneAccountChanged: phoneAccount=%s", phoneAccount);
        boolean isVideoNowSupported = phoneAccount.hasCapabilities(
                PhoneAccount.CAPABILITY_VIDEO_CALLING);
        mCalls.stream()
                .filter(c -> phoneAccount.getAccountHandle().equals(c.getTargetPhoneAccount()))
                .forEach(c -> c.setVideoCallingSupportedByPhoneAccount(isVideoNowSupported));
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -126,6 +126,8 @@ public class PhoneAccountRegistrar {
                                             PhoneAccountHandle handle) {}
        public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar,
                                             PhoneAccountHandle handle) {}
        public void onPhoneAccountChanged(PhoneAccountRegistrar registrar,
                PhoneAccount phoneAccount) {}
    }

    /**
@@ -743,6 +745,8 @@ public class PhoneAccountRegistrar {
        fireAccountsChanged();
        if (isNewAccount) {
            fireAccountRegistered(account.getAccountHandle());
        } else {
            fireAccountChanged(account);
        }
    }

@@ -804,6 +808,12 @@ public class PhoneAccountRegistrar {
        }
    }

    private void fireAccountChanged(PhoneAccount account) {
        for (Listener l : mListeners) {
            l.onPhoneAccountChanged(this, account);
        }
    }

    private void fireAccountUnRegistered(PhoneAccountHandle handle) {
        for (Listener l : mListeners) {
            l.onPhoneAccountUnRegistered(this, handle);
+66 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.telecom.tests;

import static junit.framework.TestCase.fail;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -102,9 +104,12 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@RunWith(JUnit4.class)
public class CallsManagerTest extends TelecomTestCase {
    private static final int TEST_TIMEOUT = 5000;  // milliseconds
    private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle(
            ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1");
    private static final PhoneAccountHandle SIM_2_HANDLE = new PhoneAccountHandle(
@@ -960,6 +965,67 @@ public class CallsManagerTest extends TelecomTestCase {
        assertTrue(mCallsManager.isInEmergencyCall());
    }

    /**
     * Verifies that changes to a {@link PhoneAccount}'s
     * {@link PhoneAccount#CAPABILITY_VIDEO_CALLING} capability will be reflected on a call.
     * @throws Exception
     */
    @SmallTest
    @Test
    public void testPhoneAccountVideoAvailability() throws InterruptedException {
        Call ongoingCall = addSpyCall(); // adds to SIM_2_ACCT
        LinkedBlockingQueue<Integer> capabilitiesQueue = new LinkedBlockingQueue<>(1);
        ongoingCall.addListener(new Call.ListenerBase() {
            @Override
            public void onConnectionCapabilitiesChanged(Call call) {
                try {
                    Log.i("TYLER", "Listener got " + call.getConnectionCapabilities());
                    capabilitiesQueue.put(call.getConnectionCapabilities());
                } catch (InterruptedException e) {
                    fail();
                }
            }
        });

        // Lets make the phone account video capable.
        PhoneAccount videoCapableAccount = new PhoneAccount.Builder(SIM_2_ACCOUNT)
                .setCapabilities(SIM_2_ACCOUNT.getCapabilities()
                        | PhoneAccount.CAPABILITY_VIDEO_CALLING)
                .build();
        mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
                videoCapableAccount);
        // Absorb first update; it'll be from when phone account changed initially (since we force
        // a capabilities update.
        int newCapabilities = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);

        // Lets pretend the ConnectionService made it video capable as well.
        ongoingCall.setConnectionCapabilities(
                Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
        newCapabilities = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
        assertTrue(Connection.can(newCapabilities,
                Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
        assertTrue(ongoingCall.isVideoCallingSupportedByPhoneAccount());

        // Fire a changed event for the phone account making it not capable.
        mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
                SIM_2_ACCOUNT);
        newCapabilities = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
        assertFalse(Connection.can(newCapabilities,
                Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
        assertFalse(ongoingCall.isVideoCallingSupportedByPhoneAccount());

        // Fire a change for an unrelated phone account.
        PhoneAccount anotherVideoCapableAcct = new PhoneAccount.Builder(SIM_1_ACCOUNT)
                .setCapabilities(SIM_2_ACCOUNT.getCapabilities()
                        | PhoneAccount.CAPABILITY_VIDEO_CALLING)
                .build();
        mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
                anotherVideoCapableAcct);
        // Call still should not be video capable
        assertFalse(Connection.can(ongoingCall.getConnectionCapabilities(),
                Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
    }

    private Call addSpyCallWithConnectionService(ConnectionServiceWrapper connSvr) {
        Call call = addSpyCall();
        doReturn(connSvr).when(call).getConnectionService();