1 /* 2 * Copyright (C) 2020 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.bluetooth.telephony; 18 19 import android.net.Uri; 20 import android.os.Bundle; 21 import android.os.Handler; 22 import android.telecom.Call; 23 import android.telecom.GatewayInfo; 24 import android.telecom.InCallService; 25 import android.telecom.PhoneAccountHandle; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * A proxy class of android.telecom.Call that 34 * 1) facilitates testing of the BluetoothInCallService class; We can't mock the final class 35 * Call directly; 36 * 2) Some helper functions, to let Call have same methods as com.android.server.telecom.Call 37 * 38 * This is necessary due to the "final" attribute of the Call class. In order to 39 * test the correct functioning of the BluetoothInCallService class, the final class must be put 40 * into a container that can be mocked correctly. 41 */ 42 @VisibleForTesting 43 public class BluetoothCall { 44 45 private Call mCall; 46 getCall()47 public Call getCall() { 48 return mCall; 49 } 50 setCall(Call call)51 public void setCall(Call call) { 52 mCall = call; 53 } 54 BluetoothCall(Call call)55 public BluetoothCall(Call call) { 56 mCall = call; 57 } 58 getRemainingPostDialSequence()59 public String getRemainingPostDialSequence() { 60 return mCall.getRemainingPostDialSequence(); 61 } 62 answer(int videoState)63 public void answer(int videoState) { 64 mCall.answer(videoState); 65 } 66 deflect(Uri address)67 public void deflect(Uri address) { 68 mCall.deflect(address); 69 } 70 reject(boolean rejectWithMessage, String textMessage)71 public void reject(boolean rejectWithMessage, String textMessage) { 72 mCall.reject(rejectWithMessage, textMessage); 73 } 74 disconnect()75 public void disconnect() { 76 mCall.disconnect(); 77 } 78 hold()79 public void hold() { 80 mCall.hold(); 81 } 82 unhold()83 public void unhold() { 84 mCall.unhold(); 85 } 86 enterBackgroundAudioProcessing()87 public void enterBackgroundAudioProcessing() { 88 mCall.enterBackgroundAudioProcessing(); 89 } 90 exitBackgroundAudioProcessing(boolean shouldRing)91 public void exitBackgroundAudioProcessing(boolean shouldRing) { 92 mCall.exitBackgroundAudioProcessing(shouldRing); 93 } 94 playDtmfTone(char digit)95 public void playDtmfTone(char digit) { 96 mCall.playDtmfTone(digit); 97 } 98 stopDtmfTone()99 public void stopDtmfTone() { 100 mCall.stopDtmfTone(); 101 } 102 postDialContinue(boolean proceed)103 public void postDialContinue(boolean proceed) { 104 mCall.postDialContinue(proceed); 105 } 106 phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault)107 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) { 108 mCall.phoneAccountSelected(accountHandle, setDefault); 109 } 110 conference(BluetoothCall callToConferenceWith)111 public void conference(BluetoothCall callToConferenceWith) { 112 if (callToConferenceWith != null) { 113 mCall.conference(callToConferenceWith.getCall()); 114 } 115 } 116 splitFromConference()117 public void splitFromConference() { 118 mCall.splitFromConference(); 119 } 120 mergeConference()121 public void mergeConference() { 122 mCall.mergeConference(); 123 } 124 swapConference()125 public void swapConference() { 126 mCall.swapConference(); 127 } 128 pullExternalCall()129 public void pullExternalCall() { 130 mCall.pullExternalCall(); 131 } 132 sendCallEvent(String event, Bundle extras)133 public void sendCallEvent(String event, Bundle extras) { 134 mCall.sendCallEvent(event, extras); 135 } 136 sendRttRequest()137 public void sendRttRequest() { 138 mCall.sendRttRequest(); 139 } 140 respondToRttRequest(int id, boolean accept)141 public void respondToRttRequest(int id, boolean accept) { 142 mCall.respondToRttRequest(id, accept); 143 } 144 handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras)145 public void handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras) { 146 mCall.handoverTo(toHandle, videoState, extras); 147 } 148 stopRtt()149 public void stopRtt() { 150 mCall.stopRtt(); 151 } 152 putExtras(Bundle extras)153 public void putExtras(Bundle extras) { 154 mCall.putExtras(extras); 155 } 156 putExtra(String key, boolean value)157 public void putExtra(String key, boolean value) { 158 mCall.putExtra(key, value); 159 } 160 putExtra(String key, int value)161 public void putExtra(String key, int value) { 162 mCall.putExtra(key, value); 163 } 164 putExtra(String key, String value)165 public void putExtra(String key, String value) { 166 mCall.putExtra(key, value); 167 } 168 removeExtras(List<String> keys)169 public void removeExtras(List<String> keys) { 170 mCall.removeExtras(keys); 171 } 172 removeExtras(String... keys)173 public void removeExtras(String... keys) { 174 mCall.removeExtras(keys); 175 } 176 getParentId()177 public String getParentId() { 178 Call parent = mCall.getParent(); 179 if (parent != null) { 180 return parent.getDetails().getTelecomCallId(); 181 } 182 return null; 183 } 184 getChildrenIds()185 public List<String> getChildrenIds() { 186 return getIds(mCall.getChildren()); 187 } 188 getConferenceableCalls()189 public List<String> getConferenceableCalls() { 190 return getIds(mCall.getConferenceableCalls()); 191 } 192 getState()193 public int getState() { 194 return mCall.getState(); 195 } 196 getCannedTextResponses()197 public List<String> getCannedTextResponses() { 198 return mCall.getCannedTextResponses(); 199 } 200 getVideoCall()201 public InCallService.VideoCall getVideoCall() { 202 return mCall.getVideoCall(); 203 } 204 getDetails()205 public Call.Details getDetails() { 206 return mCall.getDetails(); 207 } 208 getRttCall()209 public Call.RttCall getRttCall() { 210 return mCall.getRttCall(); 211 } 212 isRttActive()213 public boolean isRttActive() { 214 return mCall.isRttActive(); 215 } 216 registerCallback(Call.Callback callback)217 public void registerCallback(Call.Callback callback) { 218 mCall.registerCallback(callback); 219 } 220 registerCallback(Call.Callback callback, Handler handler)221 public void registerCallback(Call.Callback callback, Handler handler) { 222 mCall.registerCallback(callback, handler); 223 } 224 unregisterCallback(Call.Callback callback)225 public void unregisterCallback(Call.Callback callback) { 226 mCall.unregisterCallback(callback); 227 } 228 toString()229 public String toString() { 230 String string = mCall.toString(); 231 return string == null ? "" : string; 232 } 233 addListener(Call.Listener listener)234 public void addListener(Call.Listener listener) { 235 mCall.addListener(listener); 236 } 237 removeListener(Call.Listener listener)238 public void removeListener(Call.Listener listener) { 239 mCall.removeListener(listener); 240 } 241 getGenericConferenceActiveChildCallId()242 public String getGenericConferenceActiveChildCallId() { 243 return mCall.getGenericConferenceActiveChildCall().getDetails().getTelecomCallId(); 244 } 245 getContactDisplayName()246 public String getContactDisplayName() { 247 return mCall.getDetails().getContactDisplayName(); 248 } 249 getAccountHandle()250 public PhoneAccountHandle getAccountHandle() { 251 return mCall.getDetails().getAccountHandle(); 252 } 253 getVideoState()254 public int getVideoState() { 255 return mCall.getDetails().getVideoState(); 256 } 257 getCallerDisplayName()258 public String getCallerDisplayName() { 259 return mCall.getDetails().getCallerDisplayName(); 260 } 261 262 @Override equals(Object o)263 public boolean equals(Object o) { 264 if (o == null) { 265 return getCall() == null; 266 } 267 return o instanceof BluetoothCall && getCall() == ((BluetoothCall) o).getCall(); 268 } 269 270 // helper functions isSilentRingingRequested()271 public boolean isSilentRingingRequested() { 272 return getDetails().getExtras() != null 273 && getDetails().getExtras().getBoolean(Call.EXTRA_SILENT_RINGING_REQUESTED); 274 } 275 isConference()276 public boolean isConference() { 277 return getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE); 278 } 279 can(int capability)280 public boolean can(int capability) { 281 return getDetails().can(capability); 282 } 283 getHandle()284 public Uri getHandle() { 285 return getDetails().getHandle(); 286 } 287 getGatewayInfo()288 public GatewayInfo getGatewayInfo() { 289 return getDetails().getGatewayInfo(); 290 } 291 isIncoming()292 public boolean isIncoming() { 293 return getDetails().getCallDirection() == Call.Details.DIRECTION_INCOMING; 294 } 295 isExternalCall()296 public boolean isExternalCall() { 297 return getDetails().hasProperty(Call.Details.PROPERTY_IS_EXTERNAL_CALL); 298 } 299 getTelecomCallId()300 public String getTelecomCallId() { 301 return getDetails().getTelecomCallId(); 302 } 303 wasConferencePreviouslyMerged()304 public boolean wasConferencePreviouslyMerged() { 305 return can(Call.Details.CAPABILITY_SWAP_CONFERENCE) && 306 !can(Call.Details.CAPABILITY_MERGE_CONFERENCE); 307 } 308 getIds(List<Call> calls)309 public static List<String> getIds(List<Call> calls) { 310 List<String> result = new ArrayList<>(); 311 for (Call call : calls) { 312 if (call != null) { 313 result.add(call.getDetails().getTelecomCallId()); 314 } 315 } 316 return result; 317 } 318 } 319