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

Commit 3a863ee7 authored by Thomas Stuart's avatar Thomas Stuart
Browse files

impl transactional video API methods

Bug: 311265260
Test: CTS coverage
Change-Id: Ib2196ff4bfda7a5a779d939350a00661b121ce9c
parent 11318e56
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -29,6 +29,13 @@ flag{
  bug: "310669304"
}

flag{
  name: "transactional_video_state"
  namespace: "telecom"
  description: "when set, clients using transactional implementations will be able to set & get the video state"
  bug: "311265260"
}

flag{
  name: "business_call_composer"
  namespace: "telecom"
+47 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.server.telecom;
import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
import static android.telephony.TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE;

import static com.android.server.telecom.voip.VideoStateTranslation.VideoProfileStateToTransactionalVideoState;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -651,6 +653,36 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
     */
    private boolean mIsVideoCallingSupportedByPhoneAccount = false;

    /**
     * Indicates whether this individual calls video state can be changed as opposed to be gated
     * by the {@link PhoneAccount}.
     *
     * {@code True} if the call is Transactional && has the CallAttributes.SUPPORTS_VIDEO_CALLING
     * capability {@code false} otherwise.
     */
    private boolean mTransactionalCallSupportsVideoCalling = false;

    public void setTransactionalCallSupportsVideoCalling(CallAttributes callAttributes) {
        if (!mIsTransactionalCall) {
            Log.i(this, "setTransactionalCallSupportsVideoCalling: call is not transactional");
            return;
        }
        if (callAttributes == null) {
            Log.i(this, "setTransactionalCallSupportsVideoCalling: callAttributes is null");
            return;
        }
        if ((callAttributes.getCallCapabilities() & CallAttributes.SUPPORTS_VIDEO_CALLING)
                == CallAttributes.SUPPORTS_VIDEO_CALLING) {
            mTransactionalCallSupportsVideoCalling = true;
        } else {
            mTransactionalCallSupportsVideoCalling = false;
        }
    }

    public boolean isTransactionalCallSupportsVideoCalling() {
        return mTransactionalCallSupportsVideoCalling;
    }

    /**
     * Indicates whether or not this call can be pulled if it is an external call. If true, respect
     * the Connection Capability set by the ConnectionService. If false, override the capability
@@ -4023,6 +4055,15 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            videoState = VideoProfile.STATE_AUDIO_ONLY;
        }

        // Transactional calls have the ability to change video calling capabilities on a per-call
        // basis as opposed to ConnectionService calls which are only based on the PhoneAccount.
        if (mFlags.transactionalVideoState()
                && mIsTransactionalCall && !mTransactionalCallSupportsVideoCalling) {
            Log.i(this, "setVideoState: The transactional does NOT support video calling."
                    + " defaulted to audio (video not supported)");
            videoState = VideoProfile.STATE_AUDIO_ONLY;
        }

        // Track Video State history during the duration of the call.
        // Only update the history when the call is active or disconnected. This ensures we do
        // not include the video state history when:
@@ -4045,6 +4086,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            }
        }

        if (mFlags.transactionalVideoState()
                && mIsTransactionalCall && mTransactionalService != null) {
            int transactionalVS = VideoProfileStateToTransactionalVideoState(mVideoState);
            mTransactionalService.onVideoStateChanged(this, transactionalVS);
        }

        if (VideoProfile.isVideo(videoState)) {
            mAnalytics.setCallIsVideo(true);
        }
+3 −0
Original line number Diff line number Diff line
@@ -239,6 +239,9 @@ public class TelecomServiceImpl {
                                                callEventCallback, mCallsManager, call);

                        call.setTransactionServiceWrapper(serviceWrapper);
                        if (mFeatureFlags.transactionalVideoState()) {
                            call.setTransactionalCallSupportsVideoCalling(callAttributes);
                        }
                        ICallControl clientCallControl = serviceWrapper.getICallControl();

                        if (clientCallControl == null) {
+27 −1
Original line number Diff line number Diff line
@@ -43,10 +43,10 @@ import com.android.server.telecom.voip.EndpointChangeTransaction;
import com.android.server.telecom.voip.HoldCallTransaction;
import com.android.server.telecom.voip.EndCallTransaction;
import com.android.server.telecom.voip.MaybeHoldCallForNewCallTransaction;
import com.android.server.telecom.voip.ParallelTransaction;
import com.android.server.telecom.voip.RequestNewActiveCallTransaction;
import com.android.server.telecom.voip.SerialTransaction;
import com.android.server.telecom.voip.SetMuteStateTransaction;
import com.android.server.telecom.voip.RequestVideoStateTransaction;
import com.android.server.telecom.voip.TransactionManager;
import com.android.server.telecom.voip.VoipCallTransaction;
import com.android.server.telecom.voip.VoipCallTransactionResult;
@@ -71,6 +71,7 @@ public class TransactionalServiceWrapper implements
    public static final String ANSWER = "Answer";
    public static final String DISCONNECT = "Disconnect";
    public static final String START_STREAMING = "StartStreaming";
    public static final String REQUEST_VIDEO_STATE = "RequestVideoState";

    // CallEventCallback : Telecom --> Client (ex. voip app)
    public static final String ON_SET_ACTIVE = "onSetActive";
@@ -248,6 +249,17 @@ public class TransactionalServiceWrapper implements
            }
        }

        @Override
        public void requestVideoState(int videoState, String callId, ResultReceiver callback)
                throws RemoteException {
            try {
                Log.startSession("TSW.rVS");
                createTransactions(callId, callback, REQUEST_VIDEO_STATE, videoState);
            } finally {
                Log.endSession();
            }
        }

        private void createTransactions(String callId, ResultReceiver callback, String action,
                Object... objects) {
            Log.d(TAG, "createTransactions: callId=" + callId);
@@ -274,6 +286,11 @@ public class TransactionalServiceWrapper implements
                        addTransactionsToManager(mStreamingController.getStartStreamingTransaction(mCallsManager,
                                TransactionalServiceWrapper.this, call, mLock), callback);
                        break;
                    case REQUEST_VIDEO_STATE:
                        addTransactionsToManager(
                                new RequestVideoStateTransaction(mCallsManager, call,
                                        (int) objects[0]), callback);
                        break;
                }
            } else {
                Bundle exceptionBundle = new Bundle();
@@ -562,6 +579,15 @@ public class TransactionalServiceWrapper implements
        }
    }

    public void onVideoStateChanged(Call call, int videoState) {
        if (call != null) {
            try {
                mICallEventCallback.onVideoStateChanged(call.getId(), videoState);
            } catch (RemoteException e) {
            }
        }
    }

    public void removeCallFromWrappers(Call call) {
        if (call != null) {
            try {
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 static com.android.server.telecom.voip.VideoStateTranslation.TransactionalVideoStateToVideoProfileState;

import android.telecom.VideoProfile;
import android.util.Log;

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

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

public class RequestVideoStateTransaction extends VoipCallTransaction {

    private static final String TAG = RequestVideoStateTransaction.class.getSimpleName();
    private final Call mCall;
    private final int mVideoProfileState;

    public RequestVideoStateTransaction(CallsManager callsManager, Call call,
            int transactionalVideoState) {
        super(callsManager.getLock());
        mCall = call;
        mVideoProfileState = TransactionalVideoStateToVideoProfileState(transactionalVideoState);
    }

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

        if (isRequestingVideoTransmission(mVideoProfileState) &&
                !mCall.isVideoCallingSupportedByPhoneAccount()) {
            future.complete(new VoipCallTransactionResult(
                    VoipCallTransactionResult.RESULT_FAILED,
                    "Video calling is not supported by the target account"));
        } else if (isRequestingVideoTransmission(mVideoProfileState) &&
                !mCall.isTransactionalCallSupportsVideoCalling()) {
            future.complete(new VoipCallTransactionResult(
                    VoipCallTransactionResult.RESULT_FAILED,
                    "Video calling is not supported according to the callAttributes"));
        } else {
            mCall.setVideoState(mVideoProfileState);
            future.complete(new VoipCallTransactionResult(
                    VoipCallTransactionResult.RESULT_SUCCEED,
                    "The Video State was changed successfully"));
        }
        return future;
    }

    private boolean isRequestingVideoTransmission(int targetVideoState) {
        return targetVideoState != VideoProfile.STATE_AUDIO_ONLY;
    }
}
 No newline at end of file
Loading