Home | History | Annotate | Download | only in telephony
      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 
     17 package com.googlecode.android_scripting.facade.telephony;
     18 
     19 import java.util.ArrayList;
     20 import java.util.HashMap;
     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.Connection;
     28 import android.telecom.InCallService;
     29 import android.telecom.Phone;
     30 import android.telecom.TelecomManager;
     31 import android.telecom.VideoProfile;
     32 import android.telecom.VideoProfile.CameraCapabilities;
     33 
     34 import com.googlecode.android_scripting.Log;
     35 
     36 import com.googlecode.android_scripting.facade.EventFacade;
     37 
     38 public 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