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

Commit 349bc9d2 authored by Thomas Stuart's avatar Thomas Stuart Committed by Android (Google) Code Review
Browse files

Merge "add CallControl#answerCall" into udc-dev

parents 5627721c f94b3f86
Loading
Loading
Loading
Loading
+19 −21
Original line number Diff line number Diff line
@@ -5960,18 +5960,24 @@ public class CallsManager extends Call.ListenerBase
        }
    }

    // driver method to create and execute a new TransactionalFocusRequestCallback
    public void transactionRequestNewFocusCall(Call call,
    /**
     * Intended for ongoing or new calls that would like to go active/answered and need to
     * update the mConnectionSvrFocusMgr before setting the state
     */
    public void transactionRequestNewFocusCall(Call call, int newCallState,
            OutcomeReceiver<Boolean, CallException> callback) {
        Log.d(this, "transactionRequestNewFocusCall");
        PendingAction pendingAction = new ActionSetCallState(call, CallState.ACTIVE,
        PendingAction pendingAction = new ActionSetCallState(call, newCallState,
                "transactional ActionSetCallState");
        mConnectionSvrFocusMgr
                .requestFocus(call,
                        new TransactionalFocusRequestCallback(pendingAction, call, callback));
    }

    // request a new call focus and ensure the request was successful
    /**
     * Request a new call focus and ensure the request was successful via an OutcomeReceiver. Also,
     * include a PendingAction that will execute if the call focus change is successful.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public class TransactionalFocusRequestCallback implements
            ConnectionServiceFocusManager.RequestFocusCallback {
@@ -5990,26 +5996,18 @@ public class CallsManager extends Call.ListenerBase
        @Override
        public void onRequestFocusDone(ConnectionServiceFocusManager.CallFocus call) {
            Call currentCallFocus = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall();

            if (currentCallFocus == null) {
                Log.i(this, "TransactionalFocusRequestCallback: "
                        + "currentCallFocus is null.");
                mCallback.onError(new CallException("currentCallFocus is null",
            // verify the update was successful before updating the state
            Log.i(this, "tFRC: currentCallFocus=[%s], targetFocus=[%s]",
                    mTargetCallFocus, currentCallFocus);
            if (currentCallFocus == null ||
                    !currentCallFocus.getId().equals(mTargetCallFocus.getId())) {
                mCallback.onError(new CallException("failed to switch focus to requested call",
                        CallException.CODE_CALL_CANNOT_BE_SET_TO_ACTIVE));
                return;
            }

            Log.i(this, "TransactionalFocusRequestCallback: targetId=[%s], "
                    + "currentId=[%s]", mTargetCallFocus.getId(), currentCallFocus.getId());
            if (!currentCallFocus.getId().equals(mTargetCallFocus.getId())) {
                Log.i(this, "TransactionalFocusRequestCallback: "
                        + "currentCallFocus is not equal to targetCallFocus.");
                mCallback.onError(new CallException("current focus is not target focus",
                        CallException.CODE_CALL_CANNOT_BE_SET_TO_ACTIVE));
                return;
            }
            mPendingAction.performAction();
            mCallback.onResult(true);
            // at this point, we know the FocusManager is able to update successfully
            mPendingAction.performAction(); // set the call state
            mCallback.onResult(true); // complete the transaction
        }
    }

+32 −3
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import androidx.annotation.VisibleForTesting;

import com.android.internal.telecom.ICallControl;
import com.android.internal.telecom.ICallEventCallback;
import com.android.server.telecom.voip.AnswerCallTransaction;
import com.android.server.telecom.voip.CallEventCallbackAckTransaction;
import com.android.server.telecom.voip.EndpointChangeTransaction;
import com.android.server.telecom.voip.HoldCallTransaction;
@@ -67,7 +68,7 @@ public class TransactionalServiceWrapper implements
    // CallControl : Client (ex. voip app) --> Telecom
    public static final String SET_ACTIVE = "SetActive";
    public static final String SET_INACTIVE = "SetInactive";
    public static final String REJECT = "Reject";
    public static final String ANSWER = "Answer";
    public static final String DISCONNECT = "Disconnect";
    public static final String START_STREAMING = "StartStreaming";

@@ -75,7 +76,6 @@ public class TransactionalServiceWrapper implements
    public static final String ON_SET_ACTIVE = "onSetActive";
    public static final String ON_SET_INACTIVE = "onSetInactive";
    public static final String ON_ANSWER = "onAnswer";
    public static final String ON_REJECT = "onReject";
    public static final String ON_DISCONNECT = "onDisconnect";
    public static final String ON_STREAMING_STARTED = "onStreamingStarted";

@@ -195,6 +195,17 @@ public class TransactionalServiceWrapper implements
            }
        }

        @Override
        public void answer(int videoState, String callId, android.os.ResultReceiver callback)
                throws RemoteException {
            try {
                Log.startSession("TSW.a");
                createTransactions(callId, callback, ANSWER, videoState);
            } finally {
                Log.endSession();
            }
        }

        @Override
        public void setInactive(String callId, android.os.ResultReceiver callback)
                throws RemoteException {
@@ -238,6 +249,10 @@ public class TransactionalServiceWrapper implements
                    case SET_ACTIVE:
                        addTransactionsToManager(createSetActiveTransactions(call), callback);
                        break;
                    case ANSWER:
                        addTransactionsToManager(createSetAnswerTransactions(call,
                                (int) objects[0]), callback);
                        break;
                    case DISCONNECT:
                        addTransactionsToManager(new EndCallTransaction(mCallsManager,
                                (DisconnectCause) objects[0], call), callback);
@@ -541,13 +556,27 @@ public class TransactionalServiceWrapper implements
        // add t1. hold potential active call
        transactions.add(new HoldActiveCallForNewCallTransaction(mCallsManager, call));

        // add t2. answer current call
        // add t2. send request to set the current call active
        transactions.add(new RequestFocusTransaction(mCallsManager, call));

        // send off to Transaction Manager to process
        return new SerialTransaction(transactions);
    }

    private SerialTransaction createSetAnswerTransactions(Call call, int videoState) {
        // create list for multiple transactions
        List<VoipCallTransaction> transactions = new ArrayList<>();

        // add t1. hold potential active call
        transactions.add(new HoldActiveCallForNewCallTransaction(mCallsManager, call));

        // add t2. answer current call
        transactions.add(new AnswerCallTransaction(mCallsManager, call, videoState));

        // send off to Transaction Manager to process
        return new SerialTransaction(transactions);
    }

    /***
     *********************************************************************************************
     **                    FocusManager                                                       **
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.telecom.voip;

import android.os.OutcomeReceiver;
import android.telecom.CallException;
import android.util.Log;

import com.android.server.telecom.Call;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallsManager;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

/**
 * This transaction should be created for new incoming calls that request to go from
 * CallState.Ringing to CallState.Answered.  Before changing the CallState, the focus manager must
 * be updated. Once the focus manager updates, the call state will be set.  If there is an issue
 * answering the call, the transaction will fail.
 */
public class AnswerCallTransaction extends VoipCallTransaction {

    private static final String TAG = AnswerCallTransaction.class.getSimpleName();
    private final CallsManager mCallsManager;
    private final Call mCall;
    private final int mVideoState;

    public AnswerCallTransaction(CallsManager callsManager, Call call, int videoState) {
        mCallsManager = callsManager;
        mCall = call;
        mVideoState = videoState;
    }

    @Override
    public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) {
        Log.d(TAG, "processTransaction");
        CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();

        mCall.setVideoState(mVideoState);

        mCallsManager.transactionRequestNewFocusCall(mCall, CallState.ANSWERED,
                new OutcomeReceiver<>() {
            @Override
            public void onResult(Boolean result) {
                Log.d(TAG, "processTransaction: onResult");
                future.complete(new VoipCallTransactionResult(
                        VoipCallTransactionResult.RESULT_SUCCEED, null));
            }

            @Override
            public void onError(CallException exception) {
                Log.d(TAG, "processTransaction: onError");
                future.complete(new VoipCallTransactionResult(
                        exception.getCode(), exception.getMessage()));
            }
        });

        return future;
    }
}
 No newline at end of file
+3 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.telecom.CallException;
import android.util.Log;

import com.android.server.telecom.Call;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallsManager;

import java.util.concurrent.CompletableFuture;
@@ -42,7 +43,8 @@ public class RequestFocusTransaction extends VoipCallTransaction {
        Log.d(TAG, "processTransaction");
        CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();

        mCallsManager.transactionRequestNewFocusCall(mCall, new OutcomeReceiver<>() {
        mCallsManager.transactionRequestNewFocusCall(mCall, CallState.ACTIVE,
                new OutcomeReceiver<>() {
            @Override
            public void onResult(Boolean result) {
                Log.d(TAG, "processTransaction: onResult");
+18 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.PhoneNumberUtilsAdapter;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.ui.ToastFactory;
import com.android.server.telecom.voip.AnswerCallTransaction;
import com.android.server.telecom.voip.EndCallTransaction;
import com.android.server.telecom.voip.HoldCallTransaction;
import com.android.server.telecom.voip.IncomingCallTransaction;
@@ -152,7 +153,23 @@ public class TransactionTests extends TelecomTestCase {

        // THEN
        verify(mCallsManager, times(1))
                .transactionRequestNewFocusCall(eq(mMockCall1), isA(OutcomeReceiver.class));
                .transactionRequestNewFocusCall(eq(mMockCall1), eq(CallState.ACTIVE),
                        isA(OutcomeReceiver.class));
    }

    @Test
    public void testAnswerCallTransaction() throws Exception {
        // GIVEN
        AnswerCallTransaction transaction =
                new AnswerCallTransaction(mCallsManager, mMockCall1, 0);

        // WHEN
        transaction.processTransaction(null);

        // THEN
        verify(mCallsManager, times(1))
                .transactionRequestNewFocusCall(eq(mMockCall1), eq(CallState.ANSWERED),
                        isA(OutcomeReceiver.class));
    }

    @Test