1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.telecom.voip; 18 19 import static android.Manifest.permission.CALL_PRIVILEGED; 20 import static android.telecom.CallAttributes.CALL_CAPABILITIES_KEY; 21 import static android.telecom.CallAttributes.DISPLAY_NAME_KEY; 22 import static android.telecom.CallException.CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME; 23 24 import static com.android.server.telecom.voip.VideoStateTranslation.TransactionalVideoStateToVideoProfileState; 25 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.os.Bundle; 30 import android.telecom.CallAttributes; 31 import android.telecom.TelecomManager; 32 import android.util.Log; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.server.telecom.Call; 36 import com.android.server.telecom.CallsManager; 37 import com.android.server.telecom.LoggedHandlerExecutor; 38 import com.android.server.telecom.flags.FeatureFlags; 39 40 import java.util.concurrent.CompletableFuture; 41 import java.util.concurrent.CompletionStage; 42 43 public class OutgoingCallTransaction extends VoipCallTransaction { 44 45 private static final String TAG = OutgoingCallTransaction.class.getSimpleName(); 46 private final String mCallId; 47 private final Context mContext; 48 private final String mCallingPackage; 49 private final CallAttributes mCallAttributes; 50 private final CallsManager mCallsManager; 51 private final Bundle mExtras; 52 private FeatureFlags mFeatureFlags; 53 setFeatureFlags(FeatureFlags featureFlags)54 public void setFeatureFlags(FeatureFlags featureFlags) { 55 mFeatureFlags = featureFlags; 56 } 57 OutgoingCallTransaction(String callId, Context context, CallAttributes callAttributes, CallsManager callsManager, Bundle extras, FeatureFlags featureFlags)58 public OutgoingCallTransaction(String callId, Context context, CallAttributes callAttributes, 59 CallsManager callsManager, Bundle extras, FeatureFlags featureFlags) { 60 super(callsManager.getLock()); 61 mCallId = callId; 62 mContext = context; 63 mCallAttributes = callAttributes; 64 mCallsManager = callsManager; 65 mExtras = extras; 66 mCallingPackage = mContext.getOpPackageName(); 67 mFeatureFlags = featureFlags; 68 } 69 OutgoingCallTransaction(String callId, Context context, CallAttributes callAttributes, CallsManager callsManager, FeatureFlags featureFlags)70 public OutgoingCallTransaction(String callId, Context context, CallAttributes callAttributes, 71 CallsManager callsManager, FeatureFlags featureFlags) { 72 this(callId, context, callAttributes, callsManager, new Bundle(), featureFlags); 73 } 74 75 @Override processTransaction(Void v)76 public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) { 77 Log.d(TAG, "processTransaction"); 78 79 final boolean hasCallPrivilegedPermission = mContext.checkCallingPermission( 80 CALL_PRIVILEGED) == PackageManager.PERMISSION_GRANTED; 81 82 final Intent intent = new Intent(hasCallPrivilegedPermission ? 83 Intent.ACTION_CALL_PRIVILEGED : Intent.ACTION_CALL, mCallAttributes.getAddress()); 84 85 if (mCallsManager.isOutgoingCallPermitted(mCallAttributes.getPhoneAccountHandle())) { 86 Log.d(TAG, "processTransaction: outgoing call permitted"); 87 88 CompletableFuture<Call> callFuture = 89 mCallsManager.startOutgoingCall(mCallAttributes.getAddress(), 90 mCallAttributes.getPhoneAccountHandle(), 91 generateExtras(mCallAttributes), 92 mCallAttributes.getPhoneAccountHandle().getUserHandle(), 93 intent, 94 mCallingPackage); 95 96 if (callFuture == null) { 97 return CompletableFuture.completedFuture( 98 new VoipCallTransactionResult( 99 CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME, 100 "incoming call not permitted at the current time")); 101 } 102 CompletionStage<VoipCallTransactionResult> result = callFuture.thenComposeAsync( 103 (call) -> { 104 105 Log.d(TAG, "processTransaction: completing future"); 106 107 if (call == null) { 108 Log.d(TAG, "processTransaction: call is null"); 109 return CompletableFuture.completedFuture( 110 new VoipCallTransactionResult( 111 CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME, 112 "call could not be created at this time")); 113 } else { 114 Log.d(TAG, "processTransaction: call done. id=" + call.getId()); 115 } 116 117 return CompletableFuture.completedFuture( 118 new VoipCallTransactionResult( 119 VoipCallTransactionResult.RESULT_SUCCEED, 120 call, null)); 121 } 122 , new LoggedHandlerExecutor(mHandler, "OCT.pT", null)); 123 124 return result; 125 } else { 126 return CompletableFuture.completedFuture( 127 new VoipCallTransactionResult( 128 CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME, 129 "incoming call not permitted at the current time")); 130 131 } 132 } 133 134 @VisibleForTesting generateExtras(CallAttributes callAttributes)135 public Bundle generateExtras(CallAttributes callAttributes) { 136 mExtras.setDefusable(true); 137 mExtras.putString(TelecomManager.TRANSACTION_CALL_ID_KEY, mCallId); 138 mExtras.putInt(CALL_CAPABILITIES_KEY, callAttributes.getCallCapabilities()); 139 if (mFeatureFlags.transactionalVideoState()) { 140 // Transactional calls need to remap the CallAttributes video state to the existing 141 // VideoProfile for consistency. 142 mExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 143 TransactionalVideoStateToVideoProfileState(callAttributes.getCallType())); 144 } else { 145 mExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 146 callAttributes.getCallType()); 147 } 148 mExtras.putCharSequence(DISPLAY_NAME_KEY, callAttributes.getDisplayName()); 149 return mExtras; 150 } 151 } 152