• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 android.telecom.cts;
18 
19 import static org.junit.Assert.assertTrue;
20 
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.telecom.Call;
24 import android.telecom.CallAudioState;
25 import android.telecom.CallEndpoint;
26 import android.telecom.InCallService;
27 import android.util.ArrayMap;
28 import android.util.Log;
29 
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.concurrent.CountDownLatch;
35 import java.util.concurrent.Semaphore;
36 import java.util.concurrent.TimeUnit;
37 
38 public class MockInCallService extends InCallService {
39     private static final long TEST_TIMEOUT = 5000L;
40     private static String LOG_TAG = "MockInCallService";
41     private final List<Call> mCalls = Collections.synchronizedList(new ArrayList<>());
42     private final List<Call> mConferenceCalls = Collections.synchronizedList(new ArrayList<>());
43     private static InCallServiceCallbacks sCallbacks;
44     private Map<Call, MockVideoCallCallback> mVideoCallCallbacks =
45             new ArrayMap<Call, MockVideoCallCallback>();
46 
47     protected static final Object sLock = new Object();
48     private static boolean mIsServiceBound = false;
49     private static CountDownLatch sBindLatch = new CountDownLatch(1);
50     private static CountDownLatch sUnbindLatch = new CountDownLatch(1);
51     private boolean mEndpointIsMute = false;
52 
53     public static abstract class InCallServiceCallbacks {
54         private MockInCallService mService;
55         public Semaphore lock = new Semaphore(0);
56 
onCallAdded(Call call, int numCalls)57         public void onCallAdded(Call call, int numCalls) {};
onCallRemoved(Call call, int numCalls)58         public void onCallRemoved(Call call, int numCalls) {};
onCallStateChanged(Call call, int state)59         public void onCallStateChanged(Call call, int state) {};
onParentChanged(Call call, Call parent)60         public void onParentChanged(Call call, Call parent) {};
onChildrenChanged(Call call, List<Call> children)61         public void onChildrenChanged(Call call, List<Call> children) {};
onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls)62         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {};
onCallDestroyed(Call call)63         public void onCallDestroyed(Call call) {};
onDetailsChanged(Call call, Call.Details details)64         public void onDetailsChanged(Call call, Call.Details details) {};
onCanAddCallsChanged(boolean canAddCalls)65         public void onCanAddCallsChanged(boolean canAddCalls) {}
onBringToForeground(boolean showDialpad)66         public void onBringToForeground(boolean showDialpad) {}
onCallAudioStateChanged(CallAudioState audioState)67         public void onCallAudioStateChanged(CallAudioState audioState) {}
onPostDialWait(Call call, String remainingPostDialSequence)68         public void onPostDialWait(Call call, String remainingPostDialSequence) {}
onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses)69         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
onSilenceRinger()70         public void onSilenceRinger() {}
onConnectionEvent(Call call, String event, Bundle extras)71         public void onConnectionEvent(Call call, String event, Bundle extras) {}
onRttModeChanged(Call call, int mode)72         public void onRttModeChanged(Call call, int mode) {}
onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall)73         public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) {}
onRttRequest(Call call, int id)74         public void onRttRequest(Call call, int id) {}
onRttInitiationFailure(Call call, int reason)75         public void onRttInitiationFailure(Call call, int reason) {}
onHandoverComplete(Call call)76         public void onHandoverComplete(Call call) {}
onHandoverFailed(Call call, int failureReason)77         public void onHandoverFailed(Call call, int failureReason) {}
onCallEndpointChanged(CallEndpoint callEndpoint)78         public void onCallEndpointChanged(CallEndpoint callEndpoint) {}
onAvailableCallEndpointsChanged(List<CallEndpoint> availableEndpoints)79         public void onAvailableCallEndpointsChanged(List<CallEndpoint> availableEndpoints) {}
onMuteStateChanged(boolean isMuted)80         public void onMuteStateChanged(boolean isMuted) {}
81 
getService()82         final public MockInCallService getService() {
83             return mService;
84         }
85 
setService(MockInCallService service)86         final public void setService(MockInCallService service) {
87             mService = service;
88         }
89 
resetLock()90         public void resetLock() {
91             lock = new Semaphore(0);
92         }
93 
resetLatch()94         public void resetLatch() {
95             sBindLatch = new CountDownLatch(1);
96             sUnbindLatch = new CountDownLatch(1);
97         }
98 
waitForUnbind()99         public boolean waitForUnbind() {
100             try {
101                 return sUnbindLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
102             } catch (InterruptedException e) {
103                 return false;
104             }
105         }
106     }
107 
108     /**
109      * Note that the super implementations of the callback methods are all no-ops, but we call
110      * them anyway to make sure that the CTS coverage tool detects that we are testing them.
111      */
112     private Call.Callback mCallCallback = new Call.Callback() {
113         @Override
114         public void onStateChanged(Call call, int state) {
115             super.onStateChanged(call, state);
116             if (getCallbacks() != null) {
117                 getCallbacks().onCallStateChanged(call, state);
118             }
119         }
120 
121         @Override
122         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {
123             super.onVideoCallChanged(call, videoCall);
124             saveVideoCall(call, videoCall);
125         }
126 
127         @Override
128         public void onParentChanged(Call call, Call parent) {
129             super.onParentChanged(call, parent);
130             if (getCallbacks() != null) {
131                 getCallbacks().onParentChanged(call, parent);
132             }
133         }
134 
135         @Override
136         public void onChildrenChanged(Call call, List<Call> children) {
137             super.onChildrenChanged(call, children);
138             if (getCallbacks() != null) {
139                 getCallbacks().onChildrenChanged(call, children);
140             }
141         }
142 
143         @Override
144         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
145             super.onConferenceableCallsChanged(call, conferenceableCalls);
146             if (getCallbacks() != null) {
147                 getCallbacks().onConferenceableCallsChanged(call, conferenceableCalls);
148             }
149         }
150 
151         @Override
152         public void onCallDestroyed(Call call) {
153             super.onCallDestroyed(call);
154             if (getCallbacks() != null) {
155                 getCallbacks().onCallDestroyed(call);
156             }
157         }
158 
159         @Override
160         public void onDetailsChanged(Call call, Call.Details details) {
161             super.onDetailsChanged(call, details);
162             if (getCallbacks() != null) {
163                 getCallbacks().onDetailsChanged(call, details);
164             }
165         }
166 
167         @Override
168         public void onPostDialWait(Call call, String remainingPostDialSequence) {
169             super.onPostDialWait(call, remainingPostDialSequence);
170             if (getCallbacks() != null) {
171                 getCallbacks().onPostDialWait(call, remainingPostDialSequence);
172             }
173         }
174 
175         @Override
176         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
177             super.onCannedTextResponsesLoaded(call, cannedTextResponses);
178             if (getCallbacks() != null) {
179                 getCallbacks().onCannedTextResponsesLoaded(call, cannedTextResponses);
180             }
181         }
182 
183         @Override
184         public void onConnectionEvent(Call call, String event, Bundle extras) {
185             Log.i(LOG_TAG, String.format("onConnectionEvent: call=[%s], event=[%s]",
186                     call, event));
187             super.onConnectionEvent(call, event, extras);
188             if (getCallbacks() != null) {
189                 getCallbacks().onConnectionEvent(call, event, extras);
190             }
191         }
192 
193         @Override
194         public void onRttModeChanged(Call call, int mode) {
195             super.onRttModeChanged(call, mode);
196             if (getCallbacks() != null) {
197                 getCallbacks().onRttModeChanged(call, mode);
198             }
199         }
200 
201         @Override
202         public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) {
203             super.onRttStatusChanged(call, enabled, rttCall);
204             if (getCallbacks() != null) {
205                 getCallbacks().onRttStatusChanged(call, enabled, rttCall);
206             }
207         }
208 
209         @Override
210         public void onRttRequest(Call call, int id) {
211             super.onRttRequest(call, id);
212             if (getCallbacks() != null) {
213                 getCallbacks().onRttRequest(call, id);
214             }
215         }
216 
217         @Override
218         public void onRttInitiationFailure(Call call, int reason) {
219             super.onRttInitiationFailure(call, reason);
220             if (getCallbacks() != null) {
221                 getCallbacks().onRttInitiationFailure(call, reason);
222             }
223         }
224 
225         @Override
226         public void onHandoverComplete(Call call) {
227             super.onHandoverComplete(call);
228             if (getCallbacks() != null) {
229                 getCallbacks().onHandoverComplete(call);
230             }
231         }
232 
233         @Override
234         public void onHandoverFailed(Call call, int failureReason) {
235             super.onHandoverFailed(call, failureReason);
236             if (getCallbacks() != null) {
237                 getCallbacks().onHandoverFailed(call, failureReason);
238             }
239         }
240     };
241 
saveVideoCall(Call call, VideoCall videoCall)242     private void saveVideoCall(Call call, VideoCall videoCall) {
243         if (videoCall != null) {
244             if (!mVideoCallCallbacks.containsKey(call)) {
245                 MockVideoCallCallback listener = new MockVideoCallCallback(call);
246                 videoCall.registerCallback(listener);
247                 mVideoCallCallbacks.put(call, listener);
248             }
249         } else {
250             mVideoCallCallbacks.remove(call);
251         }
252     }
253 
254     @Override
onBind(android.content.Intent intent)255     public android.os.IBinder onBind(android.content.Intent intent) {
256         Log.i(LOG_TAG, "Service bounded");
257         if (getCallbacks() != null) {
258             getCallbacks().setService(this);
259         }
260         mIsServiceBound = true;
261         return super.onBind(intent);
262     }
263 
264     @Override
onCallAdded(Call call)265     public void onCallAdded(Call call) {
266         Log.i(LOG_TAG, String.format("onCallAdded: call=[%s]", call));
267         super.onCallAdded(call);
268         if (call.getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE) == true) {
269             if (!mConferenceCalls.contains(call)) {
270                 mConferenceCalls.add(call);
271                 call.registerCallback(mCallCallback);
272             }
273         } else {
274             if (!mCalls.contains(call)) {
275                 Log.i(LOG_TAG, "added call to list");
276                 mCalls.add(call);
277                 call.registerCallback(mCallCallback);
278                 VideoCall videoCall = call.getVideoCall();
279                 if (videoCall != null) {
280                     saveVideoCall(call, videoCall);
281                 }
282             }
283         }
284         if (getCallbacks() != null) {
285             getCallbacks().onCallAdded(call, mCalls.size() + mConferenceCalls.size());
286         }
287     }
288 
289     @Override
onCallRemoved(Call call)290     public void onCallRemoved(Call call) {
291         Log.i(LOG_TAG, String.format("onCallRemoved: call=[%s]", call));
292         super.onCallRemoved(call);
293         if (call.getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE) == true) {
294             mConferenceCalls.remove(call);
295         } else {
296             mCalls.remove(call);
297         }
298         if (getCallbacks() != null) {
299             getCallbacks().onCallRemoved(call, mCalls.size() + mConferenceCalls.size());
300             saveVideoCall(call, null /* remove videoCall */);
301         }
302     }
303 
304     @Override
onCanAddCallChanged(boolean canAddCall)305     public void onCanAddCallChanged(boolean canAddCall) {
306         super.onCanAddCallChanged(canAddCall);
307         if (getCallbacks() != null) {
308             getCallbacks().onCanAddCallsChanged(canAddCall);
309         }
310     }
311 
312     @Override
onBringToForeground(boolean showDialpad)313     public void onBringToForeground(boolean showDialpad) {
314         super.onBringToForeground(showDialpad);
315         if (getCallbacks() != null) {
316             getCallbacks().onBringToForeground(showDialpad);
317         }
318     }
319 
320     @Override
onCallAudioStateChanged(CallAudioState audioState)321     public void onCallAudioStateChanged(CallAudioState audioState) {
322         super.onCallAudioStateChanged(audioState);
323         if (getCallbacks() != null) {
324             getCallbacks().onCallAudioStateChanged(audioState);
325         }
326     }
327 
328     @Override
onCallEndpointChanged(CallEndpoint callEndpoint)329     public void onCallEndpointChanged(CallEndpoint callEndpoint) {
330         super.onCallEndpointChanged(callEndpoint);
331         if (getCallbacks() != null) {
332             getCallbacks().onCallEndpointChanged(callEndpoint);
333         }
334     }
335 
336     @Override
onAvailableCallEndpointsChanged(List<CallEndpoint> availableEndpoints)337     public void onAvailableCallEndpointsChanged(List<CallEndpoint> availableEndpoints) {
338         super.onAvailableCallEndpointsChanged(availableEndpoints);
339         if (getCallbacks() != null) {
340             getCallbacks().onAvailableCallEndpointsChanged(availableEndpoints);
341         }
342     }
343 
344     @Override
onMuteStateChanged(boolean isMuted)345     public void onMuteStateChanged(boolean isMuted) {
346         super.onMuteStateChanged(isMuted);
347         mEndpointIsMute = isMuted;
348         if (getCallbacks() != null) {
349             getCallbacks().onMuteStateChanged(isMuted);
350         }
351     }
352 
353     @Override
onSilenceRinger()354     public void onSilenceRinger(){
355         super.onSilenceRinger();
356         if(getCallbacks() != null) {
357             getCallbacks().onSilenceRinger();
358         }
359     }
360 
361     /**
362      * @return the number of calls currently added to the {@code InCallService}.
363      */
getCallCount()364     public int getCallCount() {
365         return mCalls.size();
366     }
367 
368     /**
369      * @return the number of conference calls currently added to the {@code InCallService}.
370      */
getConferenceCallCount()371     public int getConferenceCallCount() {
372         return mConferenceCalls.size();
373     }
374 
375     /**
376      * @return the most recently added call that exists inside the {@code InCallService}
377      */
getLastCall()378     public Call getLastCall() {
379         if (!mCalls.isEmpty()) {
380             return mCalls.get(mCalls.size() - 1);
381         }
382         return null;
383     }
384 
getAllCalls()385     public List<Call> getAllCalls() {
386         return mCalls;
387     }
388 
getCallWithId(String id)389     public Call getCallWithId(String id) {
390         for (Call call : mCalls) {
391             if (call.getDetails().getTelecomCallId().equals(id)) {
392                 return call;
393             }
394         }
395         return null;
396     }
397 
clearCallList()398     public void clearCallList() {
399         mCalls.clear();
400     }
401 
402     /**
403      * @return the most recently added conference call that exists inside the {@code InCallService}
404      */
getLastConferenceCall()405     public Call getLastConferenceCall() {
406         if (!mConferenceCalls.isEmpty()) {
407             return mConferenceCalls.get(mConferenceCalls.size() - 1);
408         }
409         return null;
410     }
411 
disconnectLastCall()412     public void disconnectLastCall() {
413         final Call call = getLastCall();
414         if (call != null) {
415             call.disconnect();
416         }
417     }
418 
disconnectLastConferenceCall()419     public void disconnectLastConferenceCall() {
420         final Call call = getLastConferenceCall();
421         if (call != null) {
422             call.disconnect();
423         }
424     }
425 
disconnectAllCalls()426     public void disconnectAllCalls() {
427         synchronized (mCalls) {
428             for (final Call call : mCalls) {
429                 call.disconnect();
430             }
431         }
432     }
433 
disconnectAllConferenceCalls()434     public void disconnectAllConferenceCalls() {
435         synchronized (mConferenceCalls) {
436             for (final Call call : mConferenceCalls) {
437                 call.disconnect();
438             }
439         }
440     }
441 
setCallbacks(InCallServiceCallbacks callbacks)442     public static void setCallbacks(InCallServiceCallbacks callbacks) {
443         synchronized (sLock) {
444             sCallbacks = callbacks;
445         }
446     }
447 
getCallbacks()448     private InCallServiceCallbacks getCallbacks() {
449         synchronized (sLock) {
450             if (sCallbacks != null) {
451                 sCallbacks.setService(this);
452             }
453             return sCallbacks;
454         }
455     }
456 
getEndpointMuteState()457     public boolean getEndpointMuteState() {
458         return mEndpointIsMute;
459     }
460 
461     /**
462      * Determines if a video callback has been registered for the passed in call.
463      *
464      * @param call The call.
465      * @return {@code true} if a video callback has been registered.
466      */
isVideoCallbackRegistered(Call call)467     public boolean isVideoCallbackRegistered(Call call) {
468         return mVideoCallCallbacks.containsKey(call);
469     }
470 
471     /**
472      * Retrieves the video callbacks associated with a call.
473      * @param call The call.
474      * @return The {@link MockVideoCallCallback} instance associated with the call.
475      */
getVideoCallCallback(Call call)476     public MockVideoCallCallback getVideoCallCallback(Call call) {
477         return mVideoCallCallbacks.get(call);
478     }
479 
480     @Override
onUnbind(Intent intent)481     public boolean onUnbind(Intent intent) {
482         Log.i(LOG_TAG, "Service has been unbound");
483         assertTrue(mIsServiceBound);
484         mIsServiceBound = false;
485         mCalls.clear();
486         return super.onUnbind(intent);
487     }
488 
isServiceBound()489     public static boolean isServiceBound() {
490         return mIsServiceBound;
491     }
492 }
493