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