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