1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting.facade.telephony;
18 
19 import java.util.HashMap;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Set;
23 
24 import android.telecom.Call;
25 import android.telecom.Call.Details;
26 import android.telecom.CallAudioState;
27 import android.telecom.Conference;
28 import android.telecom.Connection;
29 import android.telecom.ConnectionService;
30 import android.telecom.InCallService;
31 import android.telecom.Phone;
32 import android.telecom.TelecomManager;
33 import android.telecom.VideoProfile;
34 import android.telecom.VideoProfile.CameraCapabilities;
35 
36 import com.googlecode.android_scripting.Log;
37 
38 import com.googlecode.android_scripting.facade.EventFacade;
39 
40 public class InCallServiceImpl extends InCallService {
41 
42     private static InCallServiceImpl sService = null;
43 
getService()44     public static InCallServiceImpl getService() {
45         return sService;
46     }
47 
48     public static class CallListener {
49 
50         public static final int LISTEN_CALL_ADDED   = 1 << 0;
51         public static final int LISTEN_CALL_REMOVED = 1 << 1;
52         public static final int LISTEN_ALL = LISTEN_CALL_ADDED | LISTEN_CALL_REMOVED;
53 
54         private static int sListenedEvents = 0;
55 
startListeningForEvent( int event )56         public static void startListeningForEvent( int event ) {
57             sListenedEvents |= event & LISTEN_ALL;
58         }
59 
stopListeningForEvent( int event )60         public static void stopListeningForEvent( int event ) {
61             sListenedEvents &= ~(event & LISTEN_ALL);
62         }
63 
onCallAdded(String callId, Call call)64         public static void onCallAdded(String callId, Call call) {
65             Log.d("CallListener:onCallAdded()");
66             if ((sListenedEvents & LISTEN_CALL_ADDED)
67                     == LISTEN_CALL_ADDED) {
68                 servicePostEvent(TelephonyConstants.EventTelecomCallAdded,
69                         new CallEvent<Call>(callId, call));
70             }
71         }
72 
onCallRemoved(String callId, Call call)73         public static void onCallRemoved(String callId, Call call) {
74             Log.d("CallListener:onCallRemoved()");
75             if ((sListenedEvents & LISTEN_CALL_REMOVED)
76                     == LISTEN_CALL_REMOVED) {
77                 servicePostEvent(TelephonyConstants.EventTelecomCallRemoved,
78                         new CallEvent<Call>(callId, call));
79             }
80         }
81     };
82 
83 
84     private static Object mLock = new Object();
85 
86     // Provides a return value for getCallState when no call is active
87     public static final int STATE_INVALID = -1;
88 
89     // Provides a return value for getCallQuality when input is invalid
90     public static final int QUALITY_INVALID = -1;
91 
92     // Provides a return value for getAudioRoute when input is invalid
93     public static final int INVALID_AUDIO_ROUTE = -1;
94 
95     public static final int VIDEO_STATE_AUDIO_ONLY = VideoProfile.STATE_AUDIO_ONLY;
96 
97     public static final int VIDEO_STATE_TX_ENABLED = VideoProfile.STATE_TX_ENABLED;
98 
99     public static final int VIDEO_STATE_RX_ENABLED = VideoProfile.STATE_RX_ENABLED;
100 
101     public static final int VIDEO_STATE_BIDIRECTIONAL = VideoProfile.STATE_BIDIRECTIONAL;
102 
103     public static final int VIDEO_STATE_TX_PAUSED =
104             VideoProfile.STATE_TX_ENABLED | VideoProfile.STATE_PAUSED;
105 
106     public static final int VIDEO_STATE_RX_PAUSED =
107             VideoProfile.STATE_RX_ENABLED | VideoProfile.STATE_PAUSED;
108 
109     public static final int VIDEO_STATE_BIDIRECTIONAL_PAUSED =
110             VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED;
111 
112     // Container class to return the call ID along with the event
113     public static class CallEvent<EventType> {
114 
115         private final String mCallId;
116         private final EventType mEvent;
117 
CallEvent(String callId, EventType event)118         CallEvent(String callId, EventType event) {
119             mCallId = callId;
120             mEvent = event;
121         }
122 
getCallId()123         public String getCallId() {
124             return mCallId;
125         }
126 
getEvent()127         public EventType getEvent() {
128             return mEvent;
129         }
130     }
131 
132     // Currently the same as a call event... here for future use
133     public static class VideoCallEvent<EventType> extends CallEvent<EventType> {
VideoCallEvent(String callId, EventType event)134         VideoCallEvent(String callId, EventType event) {
135             super(callId, event);
136         }
137     }
138 
139     private class CallCallback extends Call.Callback {
140 
141         // Invalid video state (valid >= 0)
142         public static final int STATE_INVALID = InCallServiceImpl.STATE_INVALID;
143 
144         public static final int EVENT_INVALID = -1;
145         public static final int EVENT_NONE = 0;
146         public static final int EVENT_STATE_CHANGED = 1 << 0;
147         public static final int EVENT_PARENT_CHANGED = 1 << 1;
148         public static final int EVENT_CHILDREN_CHANGED = 1 << 2;
149         public static final int EVENT_DETAILS_CHANGED = 1 << 3;
150         public static final int EVENT_CANNED_TEXT_RESPONSES_LOADED = 1 << 4;
151         public static final int EVENT_POST_DIAL_WAIT = 1 << 5;
152         public static final int EVENT_VIDEO_CALL_CHANGED = 1 << 6;
153         public static final int EVENT_CALL_DESTROYED = 1 << 7;
154         public static final int EVENT_CONFERENCABLE_CALLS_CHANGED = 1 << 8;
155 
156         public static final int EVENT_ALL = EVENT_STATE_CHANGED |
157                 EVENT_PARENT_CHANGED |
158                 EVENT_CHILDREN_CHANGED |
159                 EVENT_DETAILS_CHANGED |
160                 EVENT_CANNED_TEXT_RESPONSES_LOADED |
161                 EVENT_POST_DIAL_WAIT |
162                 EVENT_VIDEO_CALL_CHANGED |
163                 EVENT_DETAILS_CHANGED |
164                 EVENT_CALL_DESTROYED |
165                 EVENT_CONFERENCABLE_CALLS_CHANGED;
166 
167         private int mEvents;
168         private String mCallId;
169 
CallCallback(String callId, int events)170         public CallCallback(String callId, int events) {
171             super();
172             mEvents = events & EVENT_ALL;
173             mCallId = callId;
174         }
175 
startListeningForEvents(int events)176         public void startListeningForEvents(int events) {
177             mEvents |= events & EVENT_ALL;
178         }
179 
stopListeningForEvents(int events)180         public void stopListeningForEvents(int events) {
181             mEvents &= ~(events & EVENT_ALL);
182         }
183 
184         @Override
onStateChanged( Call call, int state)185         public void onStateChanged(
186                 Call call, int state) {
187             Log.d("CallCallback:onStateChanged()");
188             if ((mEvents & EVENT_STATE_CHANGED)
189                     == EVENT_STATE_CHANGED) {
190                 servicePostEvent(TelephonyConstants.EventTelecomCallStateChanged,
191                         new CallEvent<String>(mCallId, getCallStateString(state)));
192             }
193         }
194 
195         @Override
onParentChanged( Call call, Call parent)196         public void onParentChanged(
197                 Call call, Call parent) {
198             Log.d("CallCallback:onParentChanged()");
199             if ((mEvents & EVENT_PARENT_CHANGED)
200                     == EVENT_PARENT_CHANGED) {
201                 servicePostEvent(TelephonyConstants.EventTelecomCallParentChanged,
202                         new CallEvent<String>(mCallId, getCallId(parent)));
203             }
204         }
205 
206         @Override
onChildrenChanged( Call call, List<Call> children)207         public void onChildrenChanged(
208                 Call call, List<Call> children) {
209             Log.d("CallCallback:onChildrenChanged()");
210 
211             if ((mEvents & EVENT_CHILDREN_CHANGED)
212                     == EVENT_CHILDREN_CHANGED) {
213                 List<String> childList = new ArrayList<String>();
214 
215                 for (Call child : children) {
216                     childList.add(getCallId(child));
217                 }
218                 servicePostEvent(TelephonyConstants.EventTelecomCallChildrenChanged,
219                         new CallEvent<List<String>>(mCallId, childList));
220             }
221         }
222 
223         @Override
onDetailsChanged( Call call, Details details)224         public void onDetailsChanged(
225                 Call call, Details details) {
226             Log.d("CallCallback:onDetailsChanged()");
227 
228             if ((mEvents & EVENT_DETAILS_CHANGED)
229                     == EVENT_DETAILS_CHANGED) {
230                 servicePostEvent(TelephonyConstants.EventTelecomCallDetailsChanged,
231                         new CallEvent<Details>(mCallId, details));
232             }
233         }
234 
235         @Override
onCannedTextResponsesLoaded( Call call, List<String> cannedTextResponses)236         public void onCannedTextResponsesLoaded(
237                 Call call, List<String> cannedTextResponses) {
238             Log.d("CallCallback:onCannedTextResponsesLoaded()");
239             if ((mEvents & EVENT_CANNED_TEXT_RESPONSES_LOADED)
240                     == EVENT_CANNED_TEXT_RESPONSES_LOADED) {
241                 servicePostEvent(TelephonyConstants.EventTelecomCallCannedTextResponsesLoaded,
242                         new CallEvent<List<String>>(mCallId, cannedTextResponses));
243             }
244         }
245 
246         @Override
onPostDialWait( Call call, String remainingPostDialSequence)247         public void onPostDialWait(
248                 Call call, String remainingPostDialSequence) {
249             Log.d("CallCallback:onPostDialWait()");
250             if ((mEvents & EVENT_POST_DIAL_WAIT)
251                     == EVENT_POST_DIAL_WAIT) {
252                 servicePostEvent(TelephonyConstants.EventTelecomCallPostDialWait,
253                         new CallEvent<String>(mCallId, remainingPostDialSequence));
254             }
255         }
256 
257         @Override
onVideoCallChanged( Call call, InCallService.VideoCall videoCall)258         public void onVideoCallChanged(
259                 Call call, InCallService.VideoCall videoCall) {
260 
261             /*
262              * There is a race condition such that the lifetime of the VideoCall is not aligned with
263              * the lifetime of the underlying call object. We are using the onVideoCallChanged
264              * method as a way of determining the lifetime of the VideoCall object rather than
265              * onCallAdded/onCallRemoved.
266              */
267             Log.d("CallCallback:onVideoCallChanged()");
268 
269             if (call != null) {
270                 String callId = getCallId(call);
271                 CallContainer cc = mCallContainerMap.get(callId);
272                 if (cc == null) {
273                     Log.d(String.format("Call container returned null for callId %s", callId));
274                 }
275                 else {
276                     synchronized (mLock) {
277                         if (videoCall == null) {
278                             Log.d("Yo dawg, I heard you like null video calls.");
279                             // Try and see if the videoCall has been added/changed after firing the
280                             // callback
281                             // This probably won't work.
282                             videoCall = call.getVideoCall();
283                         }
284                         if (cc.getVideoCall() != videoCall) {
285                             if (videoCall == null) {
286                                 // VideoCall object deleted
287                                 cc.updateVideoCall(null, null);
288                                 Log.d("Removing video call from call.");
289                             }
290                             else if (cc.getVideoCall() != null) {
291                                 // Somehow we have a mismatched VideoCall ID!
292                                 Log.d("Mismatched video calls for same call ID.");
293                             }
294                             else {
295                                 Log.d("Huzzah, we have a video call!");
296 
297                                 VideoCallCallback videoCallCallback =
298                                         new VideoCallCallback(callId, VideoCallCallback.EVENT_NONE);
299 
300                                 videoCall.registerCallback(videoCallCallback);
301 
302                                 cc.updateVideoCall(
303                                         videoCall,
304                                         videoCallCallback);
305                             }
306                         }
307                         else {
308                             Log.d("Change to existing video call.");
309                         }
310 
311                     }
312                 }
313             }
314             else {
315                 Log.d("passed null call pointer to call callback");
316             }
317 
318             if ((mEvents & EVENT_VIDEO_CALL_CHANGED)
319                     == EVENT_VIDEO_CALL_CHANGED) {
320                 // TODO: b/26273778 Need to determine what to return;
321                 // probably not the whole video call
322                 servicePostEvent(TelephonyConstants.EventTelecomCallVideoCallChanged,
323                         new CallEvent<String>(mCallId, videoCall.toString()));
324             }
325         }
326 
327         @Override
onCallDestroyed(Call call)328         public void onCallDestroyed(Call call) {
329             Log.d("CallCallback:onCallDestroyed()");
330 
331             if ((mEvents & EVENT_CALL_DESTROYED)
332                     == EVENT_CALL_DESTROYED) {
333                 servicePostEvent(TelephonyConstants.EventTelecomCallDestroyed,
334                         new CallEvent<Call>(mCallId, call));
335             }
336         }
337 
338         @Override
onConferenceableCallsChanged( Call call, List<Call> conferenceableCalls)339         public void onConferenceableCallsChanged(
340                 Call call, List<Call> conferenceableCalls) {
341             Log.d("CallCallback:onConferenceableCallsChanged()");
342 
343             if ((mEvents & EVENT_CONFERENCABLE_CALLS_CHANGED)
344                     == EVENT_CONFERENCABLE_CALLS_CHANGED) {
345                 List<String> confCallList = new ArrayList<String>();
346                 for (Call cc : conferenceableCalls) {
347                     confCallList.add(getCallId(cc));
348                 }
349                 servicePostEvent(TelephonyConstants.EventTelecomCallConferenceableCallsChanged,
350                         new CallEvent<List<String>>(mCallId, confCallList));
351             }
352         }
353     }
354 
355     private class VideoCallCallback extends InCallService.VideoCall.Callback {
356 
357         public static final int EVENT_INVALID = -1;
358         public static final int EVENT_NONE = 0;
359         public static final int EVENT_SESSION_MODIFY_REQUEST_RECEIVED = 1 << 0;
360         public static final int EVENT_SESSION_MODIFY_RESPONSE_RECEIVED = 1 << 1;
361         public static final int EVENT_SESSION_EVENT = 1 << 2;
362         public static final int EVENT_PEER_DIMENSIONS_CHANGED = 1 << 3;
363         public static final int EVENT_VIDEO_QUALITY_CHANGED = 1 << 4;
364         public static final int EVENT_DATA_USAGE_CHANGED = 1 << 5;
365         public static final int EVENT_CAMERA_CAPABILITIES_CHANGED = 1 << 6;
366         public static final int EVENT_ALL =
367                 EVENT_SESSION_MODIFY_REQUEST_RECEIVED |
368                 EVENT_SESSION_MODIFY_RESPONSE_RECEIVED |
369                 EVENT_SESSION_EVENT |
370                 EVENT_PEER_DIMENSIONS_CHANGED |
371                 EVENT_VIDEO_QUALITY_CHANGED |
372                 EVENT_DATA_USAGE_CHANGED |
373                 EVENT_CAMERA_CAPABILITIES_CHANGED;
374 
375         private String mCallId;
376         private int mEvents;
377 
VideoCallCallback(String callId, int listeners)378         public VideoCallCallback(String callId, int listeners) {
379 
380             mCallId = callId;
381             mEvents = listeners & EVENT_ALL;
382         }
383 
startListeningForEvents(int events)384         public void startListeningForEvents(int events) {
385             Log.d(String.format(
386                     "VideoCallCallback(%s):startListeningForEvents(%x): events:%x",
387                     mCallId, events, mEvents));
388 
389             mEvents |= events & EVENT_ALL;
390 
391         }
392 
stopListeningForEvents(int events)393         public void stopListeningForEvents(int events) {
394             mEvents &= ~(events & EVENT_ALL);
395         }
396 
397         @Override
onSessionModifyRequestReceived(VideoProfile videoProfile)398         public void onSessionModifyRequestReceived(VideoProfile videoProfile) {
399             Log.d(String.format("VideoCallCallback(%s):onSessionModifyRequestReceived()", mCallId));
400 
401             if ((mEvents & EVENT_SESSION_MODIFY_REQUEST_RECEIVED)
402                     == EVENT_SESSION_MODIFY_REQUEST_RECEIVED) {
403                 servicePostEvent(TelephonyConstants.EventTelecomVideoCallSessionModifyRequestReceived,
404                         new VideoCallEvent<VideoProfile>(mCallId, videoProfile));
405             }
406 
407         }
408 
409         @Override
onSessionModifyResponseReceived(int status, VideoProfile requestedProfile, VideoProfile responseProfile)410         public void onSessionModifyResponseReceived(int status,
411                 VideoProfile requestedProfile, VideoProfile responseProfile) {
412             Log.d("VideoCallCallback:onSessionModifyResponseReceived()");
413 
414             if ((mEvents & EVENT_SESSION_MODIFY_RESPONSE_RECEIVED)
415                     == EVENT_SESSION_MODIFY_RESPONSE_RECEIVED) {
416 
417                 HashMap<String, VideoProfile> smrrInfo = new HashMap<String, VideoProfile>();
418 
419                 smrrInfo.put("RequestedProfile", requestedProfile);
420                 smrrInfo.put("ResponseProfile", responseProfile);
421 
422                 servicePostEvent(TelephonyConstants.EventTelecomVideoCallSessionModifyResponseReceived,
423                         new VideoCallEvent<HashMap<String, VideoProfile>>(mCallId, smrrInfo));
424             }
425         }
426 
427         @Override
onCallSessionEvent(int event)428         public void onCallSessionEvent(int event) {
429             Log.d("VideoCallCallback:onCallSessionEvent()");
430 
431             String eventString = getVideoCallSessionEventString(event);
432 
433             if ((mEvents & EVENT_SESSION_EVENT)
434                     == EVENT_SESSION_EVENT) {
435                 servicePostEvent(TelephonyConstants.EventTelecomVideoCallSessionEvent,
436                         new VideoCallEvent<String>(mCallId, eventString));
437             }
438         }
439 
440         @Override
onPeerDimensionsChanged(int width, int height)441         public void onPeerDimensionsChanged(int width, int height) {
442             Log.d("VideoCallCallback:onPeerDimensionsChanged()");
443 
444             if ((mEvents & EVENT_PEER_DIMENSIONS_CHANGED)
445                     == EVENT_PEER_DIMENSIONS_CHANGED) {
446 
447                 HashMap<String, Integer> temp = new HashMap<String, Integer>();
448                 temp.put("Width", width);
449                 temp.put("Height", height);
450 
451                 servicePostEvent(TelephonyConstants.EventTelecomVideoCallPeerDimensionsChanged,
452                         new VideoCallEvent<HashMap<String, Integer>>(mCallId, temp));
453             }
454         }
455 
456         @Override
onVideoQualityChanged(int videoQuality)457         public void onVideoQualityChanged(int videoQuality) {
458             Log.d("VideoCallCallback:onVideoQualityChanged()");
459 
460             if ((mEvents & EVENT_VIDEO_QUALITY_CHANGED)
461                     == EVENT_VIDEO_QUALITY_CHANGED) {
462                 servicePostEvent(TelephonyConstants.EventTelecomVideoCallVideoQualityChanged,
463                         new VideoCallEvent<String>(mCallId,
464                                 getVideoCallQualityString(videoQuality)));
465             }
466         }
467 
468         @Override
onCallDataUsageChanged(long dataUsage)469         public void onCallDataUsageChanged(long dataUsage) {
470             Log.d("VideoCallCallback:onCallDataUsageChanged()");
471 
472             if ((mEvents & EVENT_DATA_USAGE_CHANGED)
473                     == EVENT_DATA_USAGE_CHANGED) {
474                 servicePostEvent(TelephonyConstants.EventTelecomVideoCallDataUsageChanged,
475                         new VideoCallEvent<Long>(mCallId, dataUsage));
476             }
477         }
478 
479         @Override
onCameraCapabilitiesChanged( CameraCapabilities cameraCapabilities)480         public void onCameraCapabilitiesChanged(
481                 CameraCapabilities cameraCapabilities) {
482             Log.d("VideoCallCallback:onCallDataUsageChanged()");
483 
484             if ((mEvents & EVENT_DATA_USAGE_CHANGED)
485                     == EVENT_DATA_USAGE_CHANGED) {
486                 servicePostEvent(TelephonyConstants.EventTelecomVideoCallCameraCapabilities,
487                         new VideoCallEvent<CameraCapabilities>(mCallId, cameraCapabilities));
488             }
489 
490         }
491     }
492 
493     /*
494      * Container Class for Call and CallCallback Objects
495      */
496     private class CallContainer {
497 
498         /*
499          * Call Container Members
500          */
501 
502         private Call mCall;
503         private CallCallback mCallCallback;
504         private VideoCall mVideoCall;
505         private VideoCallCallback mVideoCallCallback;
506 
507         /*
508          * Call Container Functions
509          */
510 
CallContainer(Call call, CallCallback callback, VideoCall videoCall, VideoCallCallback videoCallCallback)511         public CallContainer(Call call,
512                 CallCallback callback,
513                 VideoCall videoCall,
514                 VideoCallCallback videoCallCallback) {
515             mCall = call;
516             mCallCallback = callback;
517             mVideoCall = videoCall;
518             mVideoCallCallback = videoCallCallback;
519         }
520 
getCall()521         public Call getCall() {
522             return mCall;
523         }
524 
getCallback()525         public CallCallback getCallback() {
526             return mCallCallback;
527         }
528 
getVideoCall()529         public InCallService.VideoCall getVideoCall() {
530             return mVideoCall;
531         }
532 
getVideoCallCallback()533         public VideoCallCallback getVideoCallCallback() {
534             return mVideoCallCallback;
535         }
536 
updateVideoCall(VideoCall videoCall, VideoCallCallback videoCallCallback)537         public void updateVideoCall(VideoCall videoCall, VideoCallCallback videoCallCallback) {
538             if (videoCall == null && videoCallCallback != null) {
539                 Log.d("UpdateVideoCall: videoCall and videoCallCallback are null.");
540                 return;
541             }
542             mVideoCall = videoCall;
543             mVideoCallCallback = videoCallCallback;
544         }
545     }
546 
547     /*
548      * TODO: b/26272583 Refactor so that these are instance members of the
549      * incallservice. Then we can perform null checks using the design pattern
550      * of the "manager" classes.
551      */
552 
553     private static EventFacade mEventFacade = null;
554     private static HashMap<String, CallContainer> mCallContainerMap =
555             new HashMap<String, CallContainer>();
556 
557     @Override
onCallAdded(Call call)558     public void onCallAdded(Call call) {
559         Log.d("onCallAdded: " + call.toString());
560         String id = getCallId(call);
561         Log.d("Adding " + id);
562         CallCallback callCallback = new CallCallback(id, CallCallback.EVENT_NONE);
563 
564         call.registerCallback(callCallback);
565 
566         VideoCall videoCall = call.getVideoCall();
567         VideoCallCallback videoCallCallback = null;
568 
569         if (videoCall != null) {
570             synchronized (mLock) {
571                 if (getVideoCallById(id) == null) {
572                     videoCallCallback = new VideoCallCallback(id, VideoCallCallback.EVENT_NONE);
573                     videoCall.registerCallback(videoCallCallback);
574                 }
575             }
576         }
577         else {
578             // No valid video object
579             Log.d("No Video Call provided to InCallService.");
580         }
581 
582         mCallContainerMap.put(id,
583                 new CallContainer(call,
584                         callCallback,
585                         videoCall,
586                         videoCallCallback));
587 
588         /*
589          * Once we have a call active, anchor the inCallService instance as a psuedo-singleton.
590          * Because object lifetime is not guaranteed we shouldn't do this in the
591          * constructor/destructor.
592          */
593         if (sService == null) {
594             sService = this;
595         }
596         else if (sService != this) {
597             Log.e("Multiple InCall Services Active in SL4A!");
598         }
599 
600         CallListener.onCallAdded(id, call);
601     }
602 
603     @Override
onCallRemoved(Call call)604     public void onCallRemoved(Call call) {
605         Log.d("onCallRemoved: " + call.toString());
606         String id = getCallId(call);
607         Log.d("Removing " + id);
608 
609         mCallContainerMap.remove(id);
610 
611         CallListener.onCallRemoved(id, call);
612 
613         if (mCallContainerMap.size() == 0) {
614             sService = null;
615         }
616     }
617 
setEventFacade(EventFacade facade)618     public static void setEventFacade(EventFacade facade) {
619         Log.d(String.format("setEventFacade(): Settings SL4A event facade to %s",
620                 (facade != null) ? facade.toString() : "null"));
621         mEventFacade = facade;
622     }
623 
servicePostEvent(String eventName, Object event)624     private static boolean servicePostEvent(String eventName, Object event) {
625 
626         if (mEventFacade == null) {
627             Log.d("servicePostEvent():SL4A eventFacade Is Null!!");
628             return false;
629         }
630 
631         mEventFacade.postEvent(eventName, event);
632 
633         return true;
634     }
635 
getCallId(Call call)636     public static String getCallId(Call call) {
637         if (call != null) {
638             return "Call:"+call.hashCode();
639         }
640         else
641             return "";
642     }
643 
getVideoCallId(InCallServiceImpl.VideoCall videoCall)644     public static String getVideoCallId(InCallServiceImpl.VideoCall videoCall) {
645         if (videoCall != null)
646             return "VideoCall:"+videoCall.hashCode();
647         else
648             return "";
649     }
650 
getCallById(String callId)651     private static Call getCallById(String callId) {
652 
653         CallContainer cc = mCallContainerMap.get(callId);
654 
655         if (cc != null) {
656             return cc.getCall();
657         }
658 
659         return null;
660     }
661 
getCallCallbackById(String callId)662     private static CallCallback getCallCallbackById(String callId) {
663 
664         CallContainer cc = mCallContainerMap.get(callId);
665 
666         if (cc != null) {
667             return cc.getCallback();
668         }
669 
670         return null;
671     }
672 
getVideoCallById(String callId)673     private static InCallService.VideoCall getVideoCallById(String callId) {
674 
675         CallContainer cc = mCallContainerMap.get(callId);
676 
677         if (cc != null) {
678             return cc.getVideoCall();
679 
680         }
681 
682         return null;
683     }
684 
685     private static VideoCallCallback
getVideoCallListenerById(String callId)686             getVideoCallListenerById(String callId) {
687 
688         CallContainer cc = mCallContainerMap.get(callId);
689 
690         if (cc != null) {
691             return cc.getVideoCallCallback();
692         }
693 
694         return null;
695     }
696 
697     /*
698      * Public Call/Phone Functions
699      */
700 
callDisconnect(String callId)701     public static void callDisconnect(String callId) {
702         Call c = getCallById(callId);
703         if (c == null) {
704             Log.d("callDisconnect: callId is null");
705             return;
706         }
707 
708         c.disconnect();
709     }
710 
holdCall(String callId)711     public static void holdCall(String callId) {
712         Call c = getCallById(callId);
713         if (c == null) {
714             Log.d("holdCall: callId is null");
715             return;
716         }
717         c.hold();
718     }
719 
mergeCallsInConference(String callId)720     public static void mergeCallsInConference(String callId) {
721         Call c = getCallById(callId);
722         if (c == null) {
723             Log.d("mergeCallsInConference: callId is null");
724             return;
725         }
726         c.mergeConference();
727     }
728 
splitCallFromConf(String callId)729     public static void splitCallFromConf(String callId) {
730         Call c = getCallById(callId);
731         if (c == null) {
732             Log.d("splitCallFromConf: callId is null");
733             return;
734         }
735         c.splitFromConference();
736     }
737 
unholdCall(String callId)738     public static void unholdCall(String callId) {
739         Call c = getCallById(callId);
740         if (c == null) {
741             Log.d("unholdCall: callId is null");
742             return;
743         }
744         c.unhold();
745     }
746 
joinCallsInConf(String callIdOne, String callIdTwo)747     public static void joinCallsInConf(String callIdOne, String callIdTwo) {
748         Call callOne = getCallById(callIdOne);
749         Call callTwo = getCallById(callIdTwo);
750 
751         if (callOne == null || callTwo == null) {
752             Log.d("joinCallsInConf: callOne or CallTwo is null");
753             return;
754         }
755 
756         callOne.conference(callTwo);
757     }
758 
getCallIdList()759     public static Set<String> getCallIdList() {
760         return mCallContainerMap.keySet();
761     }
762 
clearCallList()763     public static void clearCallList() {
764         mCallContainerMap.clear();
765     }
766 
callGetState(String callId)767     public static String callGetState(String callId) {
768         Call c = getCallById(callId);
769         if (c == null) {
770             return getCallStateString(STATE_INVALID);
771         }
772 
773         return getCallStateString(c.getState());
774     }
775 
callGetDetails(String callId)776     public static Call.Details callGetDetails(String callId) {
777         Call c = getCallById(callId);
778         if (c == null) {
779             Log.d(String.format("Couldn't find an active call with ID:%s", callId));
780             return null;
781         }
782 
783         return c.getDetails();
784     }
785 
callGetCallProperties(String callId)786     public static List<String> callGetCallProperties(String callId) {
787         Call.Details details = callGetDetails(callId);
788 
789         if (details == null) {
790             return null;
791         }
792 
793         return getCallPropertiesString(details.getCallProperties());
794     }
795 
callGetCallCapabilities(String callId)796     public static List<String> callGetCallCapabilities(String callId) {
797         Call.Details details = callGetDetails(callId);
798 
799         if (details == null) {
800             return null;
801         }
802 
803         return getCallCapabilitiesString(details.getCallCapabilities());
804     }
805 
806     @SuppressWarnings("deprecation")
overrideProximitySensor(Boolean screenOn)807     public static void overrideProximitySensor(Boolean screenOn) {
808         InCallServiceImpl svc = getService();
809         if (svc == null) {
810             Log.d("overrideProximitySensor: InCallServiceImpl is null.");
811             return;
812         }
813 
814         Phone phone = svc.getPhone();
815         if (phone == null) {
816             Log.d("overrideProximitySensor: phone is null.");
817             return;
818         }
819 
820         phone.setProximitySensorOff(screenOn);
821     }
822 
serviceGetCallAudioState()823     public static CallAudioState serviceGetCallAudioState() {
824         InCallServiceImpl svc = getService();
825 
826         if (svc != null) {
827             return svc.getCallAudioState();
828         }
829         else {
830             return null;
831         }
832     }
833 
834     // Wonky name due to conflict with internal function
serviceSetAudioRoute(String route)835     public static void serviceSetAudioRoute(String route) {
836         InCallServiceImpl svc = getService();
837 
838         if (svc == null) {
839             Log.d("serviceSetAudioRoute: InCallServiceImpl is null.");
840             return;
841         }
842 
843         int r = getAudioRoute(route);
844 
845         Log.d(String.format("Setting Audio Route to %s:%d", route, r));
846 
847         if (r == INVALID_AUDIO_ROUTE) {
848             Log.d(String.format("Invalid Audio route %s:%d", route, r));
849             return;
850         }
851         svc.setAudioRoute(r);
852     }
853 
callStartListeningForEvent(String callId, String strEvent)854     public static void callStartListeningForEvent(String callId, String strEvent) {
855 
856         CallCallback cl = getCallCallbackById(callId);
857 
858         if (cl == null) {
859             Log.d("callStartListeningForEvent: CallCallback is null.");
860             return;
861         }
862 
863         int event = getCallCallbackEvent(strEvent);
864 
865         if (event == CallCallback.EVENT_INVALID) {
866             Log.d("callStartListeningForEvent: event is invalid.");
867             return;
868         }
869 
870         cl.startListeningForEvents(event);
871     }
872 
callStopListeningForEvent(String callId, String strEvent)873     public static void callStopListeningForEvent(String callId, String strEvent) {
874         CallCallback cl = getCallCallbackById(callId);
875 
876         if (cl == null) {
877             Log.d("callStopListeningForEvent: CallCallback is null.");
878             return;
879         }
880 
881         int event = getCallCallbackEvent(strEvent);
882 
883         if (event == CallCallback.EVENT_INVALID) {
884             Log.d("callStopListeningForEvent: event is invalid.");
885             return;
886         }
887 
888         cl.stopListeningForEvents(event);
889     }
890 
videoCallStartListeningForEvent(String callId, String strEvent)891     public static void videoCallStartListeningForEvent(String callId, String strEvent) {
892         VideoCallCallback cl = getVideoCallListenerById(callId);
893 
894         if (cl == null) {
895             Log.d(String.format("Couldn't find a call with call id:%s", callId));
896             return;
897         }
898 
899         int event = getVideoCallCallbackEvent(strEvent);
900 
901         if (event == VideoCallCallback.EVENT_INVALID) {
902             Log.d(String.format("Failed to find a valid event:[%s]", strEvent));
903             return;
904         }
905 
906         cl.startListeningForEvents(event);
907     }
908 
videoCallStopListeningForEvent(String callId, String strEvent)909     public static void videoCallStopListeningForEvent(String callId, String strEvent) {
910         VideoCallCallback cl = getVideoCallListenerById(callId);
911 
912         if (cl == null) {
913             Log.d("videoCallStopListeningForEvent: CallCallback is null.");
914             return;
915         }
916 
917         int event = getVideoCallCallbackEvent(strEvent);
918 
919         if (event == VideoCallCallback.EVENT_INVALID) {
920             Log.d("getVideoCallCallbackEvent: event is invalid.");
921             return;
922         }
923 
924         cl.stopListeningForEvents(event);
925     }
926 
videoCallGetState(String callId)927     public static String videoCallGetState(String callId) {
928         Call c = getCallById(callId);
929 
930         int state = CallCallback.STATE_INVALID;
931 
932         if (c == null) {
933             Log.d("videoCallGetState: call is null.");
934         }
935         else {
936             state = c.getDetails().getVideoState();
937         }
938 
939         return getVideoCallStateString(state);
940     }
941 
videoCallSendSessionModifyRequest( String callId, String videoStateString, String videoQualityString)942     public static void videoCallSendSessionModifyRequest(
943             String callId, String videoStateString, String videoQualityString) {
944         VideoCall vc = getVideoCallById(callId);
945 
946         if (vc == null) {
947             Log.d("Invalid video call for call ID");
948             return;
949         }
950 
951         int videoState = getVideoCallState(videoStateString);
952         int videoQuality = getVideoCallQuality(videoQualityString);
953 
954         Log.d(String.format("Sending Modify request for %s:%d, %s:%d",
955                 videoStateString, videoState, videoQualityString, videoQuality));
956 
957         if (videoState == CallCallback.STATE_INVALID ||
958                 videoQuality == QUALITY_INVALID || videoQuality == VideoProfile.QUALITY_UNKNOWN) {
959             Log.d("Invalid session modify request!");
960             return;
961         }
962 
963         vc.sendSessionModifyRequest(new VideoProfile(videoState, videoQuality));
964     }
965 
videoCallSendSessionModifyResponse( String callId, String videoStateString, String videoQualityString)966     public static void videoCallSendSessionModifyResponse(
967             String callId, String videoStateString, String videoQualityString) {
968         VideoCall vc = getVideoCallById(callId);
969 
970         if (vc == null) {
971             Log.d("Invalid video call for call ID");
972             return;
973         }
974 
975         int videoState = getVideoCallState(videoStateString);
976         int videoQuality = getVideoCallQuality(videoQualityString);
977 
978         Log.d(String.format("Sending Modify request for %s:%d, %s:%d",
979                 videoStateString, videoState, videoQualityString, videoQuality));
980 
981         if (videoState == CallCallback.STATE_INVALID ||
982                 videoQuality == QUALITY_INVALID || videoQuality == VideoProfile.QUALITY_UNKNOWN) {
983             Log.d("Invalid session modify request!");
984             return;
985         }
986 
987         vc.sendSessionModifyResponse(new VideoProfile(videoState, videoQuality));
988     }
989 
callAnswer(String callId, String videoState)990     public static void callAnswer(String callId, String videoState) {
991         Call c = getCallById(callId);
992 
993         if (c == null) {
994             Log.d("callAnswer: call is null.");
995         }
996 
997         int state = getVideoCallState(videoState);
998 
999         if (state == CallCallback.STATE_INVALID) {
1000             Log.d("callAnswer: video state is invalid.");
1001             state = VideoProfile.STATE_AUDIO_ONLY;
1002         }
1003 
1004         c.answer(state);
1005     }
1006 
callReject(String callId, String message)1007     public static void callReject(String callId, String message) {
1008         Call c = getCallById(callId);
1009 
1010         if (c == null) {
1011             Log.d("callReject: call is null.");
1012         }
1013 
1014         c.reject((message != null) ? true : false, message);
1015     }
1016 
getCallParent(String callId)1017     public static String getCallParent(String callId) {
1018         Call c = getCallById(callId);
1019 
1020         if (c == null) {
1021             Log.d("getCallParent: call is null.");
1022             return null;
1023         }
1024         Call callParent = c.getParent();
1025         return getCallId(callParent);
1026     }
1027 
getCallChildren(String callId)1028     public static List<String> getCallChildren(String callId) {
1029         Call c = getCallById(callId);
1030 
1031         if (c == null) {
1032             Log.d("getCallChildren: call is null.");
1033             return null;
1034         }
1035         List<String> childrenList = new ArrayList<String>();
1036         List<Call> callChildren = c.getChildren();
1037         for (Call call : callChildren) {
1038             childrenList.add(getCallId(call));
1039         }
1040         return childrenList;
1041     }
1042 
swapCallsInConference(String callId)1043     public static void swapCallsInConference(String callId) {
1044         Call c = getCallById(callId);
1045         if (c == null) {
1046             Log.d("swapCallsInConference: call is null.");
1047             return;
1048         }
1049         c.swapConference();
1050     }
1051 
callPlayDtmfTone(String callId, char digit)1052     public static void callPlayDtmfTone(String callId, char digit) {
1053         Call c = getCallById(callId);
1054         if (c == null) {
1055             Log.d("callPlayDtmfTone: call is null.");
1056             return;
1057         }
1058         c.playDtmfTone(digit);
1059     }
1060 
callStopDtmfTone(String callId)1061     public static void callStopDtmfTone(String callId) {
1062         Call c = getCallById(callId);
1063         if (c == null) {
1064             Log.d("callStopDtmfTone: call is null.");
1065             return;
1066         }
1067         c.stopDtmfTone();
1068     }
1069 
callGetCannedTextResponses(String callId)1070     public static List<String> callGetCannedTextResponses(String callId) {
1071         Call c = getCallById(callId);
1072         if (c == null) {
1073             return null;
1074         }
1075 
1076         return c.getCannedTextResponses();
1077     }
1078 
1079     /*
1080      * String Mapping Functions for Facade Parameter Translation
1081      */
1082 
getVideoCallStateString(int state)1083     public static String getVideoCallStateString(int state) {
1084         switch (state) {
1085             case VIDEO_STATE_AUDIO_ONLY:
1086                 return TelephonyConstants.VT_STATE_AUDIO_ONLY;
1087             case VIDEO_STATE_TX_ENABLED:
1088                 return TelephonyConstants.VT_STATE_TX_ENABLED;
1089             case VIDEO_STATE_RX_ENABLED:
1090                 return TelephonyConstants.VT_STATE_RX_ENABLED;
1091             case VIDEO_STATE_BIDIRECTIONAL:
1092                 return TelephonyConstants.VT_STATE_BIDIRECTIONAL;
1093             case VIDEO_STATE_TX_PAUSED:
1094                 return TelephonyConstants.VT_STATE_TX_PAUSED;
1095             case VIDEO_STATE_RX_PAUSED:
1096                 return TelephonyConstants.VT_STATE_RX_PAUSED;
1097             case VIDEO_STATE_BIDIRECTIONAL_PAUSED:
1098                 return TelephonyConstants.VT_STATE_BIDIRECTIONAL_PAUSED;
1099             default:
1100         }
1101         Log.d("getVideoCallStateString: state is invalid.");
1102         return TelephonyConstants.VT_STATE_STATE_INVALID;
1103     }
1104 
getVideoCallState(String state)1105     public static int getVideoCallState(String state) {
1106         switch (state.toUpperCase()) {
1107             case TelephonyConstants.VT_STATE_AUDIO_ONLY:
1108                 return VIDEO_STATE_AUDIO_ONLY;
1109             case TelephonyConstants.VT_STATE_TX_ENABLED:
1110                 return VIDEO_STATE_TX_ENABLED;
1111             case TelephonyConstants.VT_STATE_RX_ENABLED:
1112                 return VIDEO_STATE_RX_ENABLED;
1113             case TelephonyConstants.VT_STATE_BIDIRECTIONAL:
1114                 return VIDEO_STATE_BIDIRECTIONAL;
1115             case TelephonyConstants.VT_STATE_TX_PAUSED:
1116                 return VIDEO_STATE_TX_PAUSED;
1117             case TelephonyConstants.VT_STATE_RX_PAUSED:
1118                 return VIDEO_STATE_RX_PAUSED;
1119             case TelephonyConstants.VT_STATE_BIDIRECTIONAL_PAUSED:
1120                 return VIDEO_STATE_BIDIRECTIONAL_PAUSED;
1121 
1122             default:
1123         }
1124         Log.d("getVideoCallState: state is invalid.");
1125         return CallCallback.STATE_INVALID;
1126     }
1127 
getVideoCallQuality(String quality)1128     private static int getVideoCallQuality(String quality) {
1129 
1130         switch (quality.toUpperCase()) {
1131             case TelephonyConstants.VT_VIDEO_QUALITY_UNKNOWN:
1132                 return VideoProfile.QUALITY_UNKNOWN;
1133             case TelephonyConstants.VT_VIDEO_QUALITY_HIGH:
1134                 return VideoProfile.QUALITY_HIGH;
1135             case TelephonyConstants.VT_VIDEO_QUALITY_MEDIUM:
1136                 return VideoProfile.QUALITY_MEDIUM;
1137             case TelephonyConstants.VT_VIDEO_QUALITY_LOW:
1138                 return VideoProfile.QUALITY_LOW;
1139             case TelephonyConstants.VT_VIDEO_QUALITY_DEFAULT:
1140                 return VideoProfile.QUALITY_DEFAULT;
1141             default:
1142         }
1143         Log.d("getVideoCallQuality: quality is invalid.");
1144         return QUALITY_INVALID;
1145     }
1146 
getVideoCallQualityString(int quality)1147     public static String getVideoCallQualityString(int quality) {
1148         switch (quality) {
1149             case VideoProfile.QUALITY_UNKNOWN:
1150                 return TelephonyConstants.VT_VIDEO_QUALITY_UNKNOWN;
1151             case VideoProfile.QUALITY_HIGH:
1152                 return TelephonyConstants.VT_VIDEO_QUALITY_HIGH;
1153             case VideoProfile.QUALITY_MEDIUM:
1154                 return TelephonyConstants.VT_VIDEO_QUALITY_MEDIUM;
1155             case VideoProfile.QUALITY_LOW:
1156                 return TelephonyConstants.VT_VIDEO_QUALITY_LOW;
1157             case VideoProfile.QUALITY_DEFAULT:
1158                 return TelephonyConstants.VT_VIDEO_QUALITY_DEFAULT;
1159             default:
1160         }
1161         Log.d("getVideoCallQualityString: quality is invalid.");
1162         return TelephonyConstants.VT_VIDEO_QUALITY_INVALID;
1163     }
1164 
getCallCallbackEvent(String event)1165     private static int getCallCallbackEvent(String event) {
1166 
1167         switch (event.toUpperCase()) {
1168             case "EVENT_STATE_CHANGED":
1169                 return CallCallback.EVENT_STATE_CHANGED;
1170             case "EVENT_PARENT_CHANGED":
1171                 return CallCallback.EVENT_PARENT_CHANGED;
1172             case "EVENT_CHILDREN_CHANGED":
1173                 return CallCallback.EVENT_CHILDREN_CHANGED;
1174             case "EVENT_DETAILS_CHANGED":
1175                 return CallCallback.EVENT_DETAILS_CHANGED;
1176             case "EVENT_CANNED_TEXT_RESPONSES_LOADED":
1177                 return CallCallback.EVENT_CANNED_TEXT_RESPONSES_LOADED;
1178             case "EVENT_POST_DIAL_WAIT":
1179                 return CallCallback.EVENT_POST_DIAL_WAIT;
1180             case "EVENT_VIDEO_CALL_CHANGED":
1181                 return CallCallback.EVENT_VIDEO_CALL_CHANGED;
1182             case "EVENT_CALL_DESTROYED":
1183                 return CallCallback.EVENT_CALL_DESTROYED;
1184             case "EVENT_CONFERENCABLE_CALLS_CHANGED":
1185                 return CallCallback.EVENT_CONFERENCABLE_CALLS_CHANGED;
1186         }
1187         Log.d("getCallCallbackEvent: event is invalid.");
1188         return CallCallback.EVENT_INVALID;
1189     }
1190 
getCallCallbackEventString(int event)1191     public static String getCallCallbackEventString(int event) {
1192 
1193         switch (event) {
1194             case CallCallback.EVENT_STATE_CHANGED:
1195                 return "EVENT_STATE_CHANGED";
1196             case CallCallback.EVENT_PARENT_CHANGED:
1197                 return "EVENT_PARENT_CHANGED";
1198             case CallCallback.EVENT_CHILDREN_CHANGED:
1199                 return "EVENT_CHILDREN_CHANGED";
1200             case CallCallback.EVENT_DETAILS_CHANGED:
1201                 return "EVENT_DETAILS_CHANGED";
1202             case CallCallback.EVENT_CANNED_TEXT_RESPONSES_LOADED:
1203                 return "EVENT_CANNED_TEXT_RESPONSES_LOADED";
1204             case CallCallback.EVENT_POST_DIAL_WAIT:
1205                 return "EVENT_POST_DIAL_WAIT";
1206             case CallCallback.EVENT_VIDEO_CALL_CHANGED:
1207                 return "EVENT_VIDEO_CALL_CHANGED";
1208             case CallCallback.EVENT_CALL_DESTROYED:
1209                 return "EVENT_CALL_DESTROYED";
1210             case CallCallback.EVENT_CONFERENCABLE_CALLS_CHANGED:
1211                 return "EVENT_CONFERENCABLE_CALLS_CHANGED";
1212         }
1213         Log.d("getCallCallbackEventString: event is invalid.");
1214         return "EVENT_INVALID";
1215     }
1216 
getVideoCallCallbackEvent(String event)1217     private static int getVideoCallCallbackEvent(String event) {
1218 
1219         switch (event) {
1220             case TelephonyConstants.EVENT_VIDEO_SESSION_MODIFY_REQUEST_RECEIVED:
1221                 return VideoCallCallback.EVENT_SESSION_MODIFY_REQUEST_RECEIVED;
1222             case TelephonyConstants.EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED:
1223                 return VideoCallCallback.EVENT_SESSION_MODIFY_RESPONSE_RECEIVED;
1224             case TelephonyConstants.EVENT_VIDEO_SESSION_EVENT:
1225                 return VideoCallCallback.EVENT_SESSION_EVENT;
1226             case TelephonyConstants.EVENT_VIDEO_PEER_DIMENSIONS_CHANGED:
1227                 return VideoCallCallback.EVENT_PEER_DIMENSIONS_CHANGED;
1228             case TelephonyConstants.EVENT_VIDEO_QUALITY_CHANGED:
1229                 return VideoCallCallback.EVENT_VIDEO_QUALITY_CHANGED;
1230             case TelephonyConstants.EVENT_VIDEO_DATA_USAGE_CHANGED:
1231                 return VideoCallCallback.EVENT_DATA_USAGE_CHANGED;
1232             case TelephonyConstants.EVENT_VIDEO_CAMERA_CAPABILITIES_CHANGED:
1233                 return VideoCallCallback.EVENT_CAMERA_CAPABILITIES_CHANGED;
1234         }
1235         Log.d("getVideoCallCallbackEvent: event is invalid.");
1236         return CallCallback.EVENT_INVALID;
1237     }
1238 
getVideoCallCallbackEventString(int event)1239     public static String getVideoCallCallbackEventString(int event) {
1240 
1241         switch (event) {
1242             case VideoCallCallback.EVENT_SESSION_MODIFY_REQUEST_RECEIVED:
1243                 return TelephonyConstants.EVENT_VIDEO_SESSION_MODIFY_REQUEST_RECEIVED;
1244             case VideoCallCallback.EVENT_SESSION_MODIFY_RESPONSE_RECEIVED:
1245                 return TelephonyConstants.EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED;
1246             case VideoCallCallback.EVENT_SESSION_EVENT:
1247                 return TelephonyConstants.EVENT_VIDEO_SESSION_EVENT;
1248             case VideoCallCallback.EVENT_PEER_DIMENSIONS_CHANGED:
1249                 return TelephonyConstants.EVENT_VIDEO_PEER_DIMENSIONS_CHANGED;
1250             case VideoCallCallback.EVENT_VIDEO_QUALITY_CHANGED:
1251                 return TelephonyConstants.EVENT_VIDEO_QUALITY_CHANGED;
1252             case VideoCallCallback.EVENT_DATA_USAGE_CHANGED:
1253                 return TelephonyConstants.EVENT_VIDEO_DATA_USAGE_CHANGED;
1254             case VideoCallCallback.EVENT_CAMERA_CAPABILITIES_CHANGED:
1255                 return TelephonyConstants.EVENT_VIDEO_CAMERA_CAPABILITIES_CHANGED;
1256         }
1257         Log.d("getVideoCallCallbackEventString: event is invalid.");
1258         return TelephonyConstants.EVENT_VIDEO_INVALID;
1259     }
1260 
getCallStateString(int state)1261     public static String getCallStateString(int state) {
1262         switch (state) {
1263             case Call.STATE_NEW:
1264                 return TelephonyConstants.CALL_STATE_NEW;
1265             case Call.STATE_DIALING:
1266                 return TelephonyConstants.CALL_STATE_DIALING;
1267             case Call.STATE_RINGING:
1268                 return TelephonyConstants.CALL_STATE_RINGING;
1269             case Call.STATE_HOLDING:
1270                 return TelephonyConstants.CALL_STATE_HOLDING;
1271             case Call.STATE_ACTIVE:
1272                 return TelephonyConstants.CALL_STATE_ACTIVE;
1273             case Call.STATE_DISCONNECTED:
1274                 return TelephonyConstants.CALL_STATE_DISCONNECTED;
1275             case Call.STATE_PRE_DIAL_WAIT:
1276                 return TelephonyConstants.CALL_STATE_PRE_DIAL_WAIT;
1277             case Call.STATE_CONNECTING:
1278                 return TelephonyConstants.CALL_STATE_CONNECTING;
1279             case Call.STATE_DISCONNECTING:
1280                 return TelephonyConstants.CALL_STATE_DISCONNECTING;
1281             case STATE_INVALID:
1282                 return TelephonyConstants.CALL_STATE_INVALID;
1283             default:
1284                 return TelephonyConstants.CALL_STATE_UNKNOWN;
1285         }
1286     }
1287 
getAudioRoute(String audioRoute)1288     private static int getAudioRoute(String audioRoute) {
1289         switch (audioRoute.toUpperCase()) {
1290             case TelephonyConstants.AUDIO_ROUTE_BLUETOOTH:
1291                 return CallAudioState.ROUTE_BLUETOOTH;
1292             case TelephonyConstants.AUDIO_ROUTE_EARPIECE:
1293                 return CallAudioState.ROUTE_EARPIECE;
1294             case TelephonyConstants.AUDIO_ROUTE_SPEAKER:
1295                 return CallAudioState.ROUTE_SPEAKER;
1296             case TelephonyConstants.AUDIO_ROUTE_WIRED_HEADSET:
1297                 return CallAudioState.ROUTE_WIRED_HEADSET;
1298             case TelephonyConstants.AUDIO_ROUTE_WIRED_OR_EARPIECE:
1299                 return CallAudioState.ROUTE_WIRED_OR_EARPIECE;
1300             default:
1301                 return INVALID_AUDIO_ROUTE;
1302         }
1303     }
1304 
getAudioRouteString(int audioRoute)1305     public static String getAudioRouteString(int audioRoute) {
1306         return CallAudioState.audioRouteToString(audioRoute);
1307     }
1308 
getVideoCallSessionEventString(int event)1309     public static String getVideoCallSessionEventString(int event) {
1310 
1311         switch (event) {
1312             case Connection.VideoProvider.SESSION_EVENT_RX_PAUSE:
1313                 return TelephonyConstants.SESSION_EVENT_RX_PAUSE;
1314             case Connection.VideoProvider.SESSION_EVENT_RX_RESUME:
1315                 return TelephonyConstants.SESSION_EVENT_RX_RESUME;
1316             case Connection.VideoProvider.SESSION_EVENT_TX_START:
1317                 return TelephonyConstants.SESSION_EVENT_TX_START;
1318             case Connection.VideoProvider.SESSION_EVENT_TX_STOP:
1319                 return TelephonyConstants.SESSION_EVENT_TX_STOP;
1320             case Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE:
1321                 return TelephonyConstants.SESSION_EVENT_CAMERA_FAILURE;
1322             case Connection.VideoProvider.SESSION_EVENT_CAMERA_READY:
1323                 return TelephonyConstants.SESSION_EVENT_CAMERA_READY;
1324             default:
1325                 return TelephonyConstants.SESSION_EVENT_UNKNOWN;
1326         }
1327     }
1328 
getCallCapabilityString(int capability)1329     public static String getCallCapabilityString(int capability) {
1330         switch (capability) {
1331             case Call.Details.CAPABILITY_HOLD:
1332                 return TelephonyConstants.CALL_CAPABILITY_HOLD;
1333             case Call.Details.CAPABILITY_SUPPORT_HOLD:
1334                 return TelephonyConstants.CALL_CAPABILITY_SUPPORT_HOLD;
1335             case Call.Details.CAPABILITY_MERGE_CONFERENCE:
1336                 return TelephonyConstants.CALL_CAPABILITY_MERGE_CONFERENCE;
1337             case Call.Details.CAPABILITY_SWAP_CONFERENCE:
1338                 return TelephonyConstants.CALL_CAPABILITY_SWAP_CONFERENCE;
1339             case Call.Details.CAPABILITY_UNUSED_1:
1340                 return TelephonyConstants.CALL_CAPABILITY_UNUSED_1;
1341             case Call.Details.CAPABILITY_RESPOND_VIA_TEXT:
1342                 return TelephonyConstants.CALL_CAPABILITY_RESPOND_VIA_TEXT;
1343             case Call.Details.CAPABILITY_MUTE:
1344                 return TelephonyConstants.CALL_CAPABILITY_MUTE;
1345             case Call.Details.CAPABILITY_MANAGE_CONFERENCE:
1346                 return TelephonyConstants.CALL_CAPABILITY_MANAGE_CONFERENCE;
1347             case Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX:
1348                 return TelephonyConstants.CALL_CAPABILITY_SUPPORTS_VT_LOCAL_RX;
1349             case Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX:
1350                 return TelephonyConstants.CALL_CAPABILITY_SUPPORTS_VT_LOCAL_TX;
1351             case Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL:
1352                 return TelephonyConstants.CALL_CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL;
1353             case Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX:
1354                 return TelephonyConstants.CALL_CAPABILITY_SUPPORTS_VT_REMOTE_RX;
1355             case Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX:
1356                 return TelephonyConstants.CALL_CAPABILITY_SUPPORTS_VT_REMOTE_TX;
1357             case Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL:
1358                 return TelephonyConstants.CALL_CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL;
1359             case Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE:
1360                 return TelephonyConstants.CALL_CAPABILITY_SEPARATE_FROM_CONFERENCE;
1361             case Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE:
1362                 return TelephonyConstants.CALL_CAPABILITY_DISCONNECT_FROM_CONFERENCE;
1363             case Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO:
1364                 return TelephonyConstants.CALL_CAPABILITY_SPEED_UP_MT_AUDIO;
1365             case Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO:
1366                 return TelephonyConstants.CALL_CAPABILITY_CAN_UPGRADE_TO_VIDEO;
1367             case Call.Details.CAPABILITY_CAN_PAUSE_VIDEO:
1368                 return TelephonyConstants.CALL_CAPABILITY_CAN_PAUSE_VIDEO;
1369         }
1370         return TelephonyConstants.CALL_CAPABILITY_UNKOWN;
1371     }
1372 
getCallCapabilitiesString(int capabilities)1373     public static List<String> getCallCapabilitiesString(int capabilities) {
1374         final int[] capabilityConstants = new int[] {
1375                 Call.Details.CAPABILITY_HOLD,
1376                 Call.Details.CAPABILITY_SUPPORT_HOLD,
1377                 Call.Details.CAPABILITY_MERGE_CONFERENCE,
1378                 Call.Details.CAPABILITY_SWAP_CONFERENCE,
1379                 Call.Details.CAPABILITY_UNUSED_1,
1380                 Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
1381                 Call.Details.CAPABILITY_MUTE,
1382                 Call.Details.CAPABILITY_MANAGE_CONFERENCE,
1383                 Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
1384                 Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
1385                 Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
1386                 Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
1387                 Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
1388                 Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
1389                 Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
1390                 Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
1391                 Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO,
1392                 Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
1393                 Call.Details.CAPABILITY_CAN_PAUSE_VIDEO
1394         };
1395 
1396         List<String> capabilityList = new ArrayList<String>();
1397 
1398         for (int capability : capabilityConstants) {
1399             if ((capabilities & capability) == capability) {
1400                 capabilityList.add(getCallCapabilityString(capability));
1401             }
1402         }
1403         return capabilityList;
1404     }
1405 
getCallPropertyString(int property)1406     public static String getCallPropertyString(int property) {
1407 
1408         switch (property) {
1409             case Call.Details.PROPERTY_CONFERENCE:
1410                 return TelephonyConstants.CALL_PROPERTY_CONFERENCE;
1411             case Call.Details.PROPERTY_GENERIC_CONFERENCE:
1412                 return TelephonyConstants.CALL_PROPERTY_GENERIC_CONFERENCE;
1413             case Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE:
1414                 return TelephonyConstants.CALL_PROPERTY_EMERGENCY_CALLBACK_MODE;
1415             case Call.Details.PROPERTY_WIFI:
1416                 return TelephonyConstants.CALL_PROPERTY_WIFI;
1417             case Call.Details.PROPERTY_HIGH_DEF_AUDIO:
1418                 return TelephonyConstants.CALL_PROPERTY_HIGH_DEF_AUDIO;
1419             default:
1420                 return TelephonyConstants.CALL_PROPERTY_UNKNOWN;
1421         }
1422     }
1423 
getCallPropertiesString(int properties)1424     public static List<String> getCallPropertiesString(int properties) {
1425         final int[] propertyConstants = new int[] {
1426                 Call.Details.PROPERTY_CONFERENCE,
1427                 Call.Details.PROPERTY_GENERIC_CONFERENCE,
1428                 Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
1429                 Call.Details.PROPERTY_WIFI,
1430                 Call.Details.PROPERTY_HIGH_DEF_AUDIO
1431         };
1432 
1433         List<String> propertyList = new ArrayList<String>();
1434 
1435         for (int property : propertyConstants) {
1436             if ((properties & property) == property) {
1437                 propertyList.add(getCallPropertyString(property));
1438             }
1439         }
1440 
1441         return propertyList;
1442     }
1443 
getCallPresentationInfoString(int presentation)1444     public static String getCallPresentationInfoString(int presentation) {
1445         switch (presentation) {
1446             case TelecomManager.PRESENTATION_ALLOWED:
1447                 return TelephonyConstants.CALL_PRESENTATION_ALLOWED;
1448             case TelecomManager.PRESENTATION_RESTRICTED:
1449                 return TelephonyConstants.CALL_PRESENTATION_RESTRICTED;
1450             case TelecomManager.PRESENTATION_PAYPHONE:
1451                 return TelephonyConstants.CALL_PRESENTATION_PAYPHONE;
1452             default:
1453                 return TelephonyConstants.CALL_PRESENTATION_UNKNOWN;
1454         }
1455     }
1456 }
1457