• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.incallui;
18 
19 import com.android.contacts.common.CallUtil;
20 import com.android.contacts.common.testing.NeededForTesting;
21 
22 import android.content.Context;
23 import android.hardware.camera2.CameraCharacteristics;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.os.Trace;
27 import android.telecom.Connection;
28 import android.telecom.DisconnectCause;
29 import android.telecom.GatewayInfo;
30 import android.telecom.InCallService.VideoCall;
31 import android.telecom.PhoneAccount;
32 import android.telecom.PhoneAccountHandle;
33 import android.telecom.TelecomManager;
34 import android.telecom.VideoProfile;
35 import android.telephony.PhoneNumberUtils;
36 import android.text.TextUtils;
37 
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Objects;
42 
43 /**
44  * Describes a single call and its state.
45  */
46 @NeededForTesting
47 public class Call {
48     /* Defines different states of this call */
49     public static class State {
50         public static final int INVALID = 0;
51         public static final int NEW = 1;            /* The call is new. */
52         public static final int IDLE = 2;           /* The call is idle.  Nothing active */
53         public static final int ACTIVE = 3;         /* There is an active call */
54         public static final int INCOMING = 4;       /* A normal incoming phone call */
55         public static final int CALL_WAITING = 5;   /* Incoming call while another is active */
56         public static final int DIALING = 6;        /* An outgoing call during dial phase */
57         public static final int REDIALING = 7;      /* Subsequent dialing attempt after a failure */
58         public static final int ONHOLD = 8;         /* An active phone call placed on hold */
59         public static final int DISCONNECTING = 9;  /* A call is being ended. */
60         public static final int DISCONNECTED = 10;  /* State after a call disconnects */
61         public static final int CONFERENCED = 11;   /* Call part of a conference call */
62         public static final int SELECT_PHONE_ACCOUNT = 12; /* Waiting for account selection */
63         public static final int CONNECTING = 13;    /* Waiting for Telecomm broadcast to finish */
64 
65 
isConnectingOrConnected(int state)66         public static boolean isConnectingOrConnected(int state) {
67             switch(state) {
68                 case ACTIVE:
69                 case INCOMING:
70                 case CALL_WAITING:
71                 case CONNECTING:
72                 case DIALING:
73                 case REDIALING:
74                 case ONHOLD:
75                 case CONFERENCED:
76                     return true;
77                 default:
78             }
79             return false;
80         }
81 
isDialing(int state)82         public static boolean isDialing(int state) {
83             return state == DIALING || state == REDIALING;
84         }
85 
toString(int state)86         public static String toString(int state) {
87             switch (state) {
88                 case INVALID:
89                     return "INVALID";
90                 case NEW:
91                     return "NEW";
92                 case IDLE:
93                     return "IDLE";
94                 case ACTIVE:
95                     return "ACTIVE";
96                 case INCOMING:
97                     return "INCOMING";
98                 case CALL_WAITING:
99                     return "CALL_WAITING";
100                 case DIALING:
101                     return "DIALING";
102                 case REDIALING:
103                     return "REDIALING";
104                 case ONHOLD:
105                     return "ONHOLD";
106                 case DISCONNECTING:
107                     return "DISCONNECTING";
108                 case DISCONNECTED:
109                     return "DISCONNECTED";
110                 case CONFERENCED:
111                     return "CONFERENCED";
112                 case SELECT_PHONE_ACCOUNT:
113                     return "SELECT_PHONE_ACCOUNT";
114                 case CONNECTING:
115                     return "CONNECTING";
116                 default:
117                     return "UNKNOWN";
118             }
119         }
120     }
121 
122     /**
123      * Defines different states of session modify requests, which are used to upgrade to video, or
124      * downgrade to audio.
125      */
126     public static class SessionModificationState {
127         public static final int NO_REQUEST = 0;
128         public static final int WAITING_FOR_RESPONSE = 1;
129         public static final int REQUEST_FAILED = 2;
130         public static final int RECEIVED_UPGRADE_TO_VIDEO_REQUEST = 3;
131         public static final int UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT = 4;
132         public static final int REQUEST_REJECTED = 5;
133     }
134 
135     public static class VideoSettings {
136         public static final int CAMERA_DIRECTION_UNKNOWN = -1;
137         public static final int CAMERA_DIRECTION_FRONT_FACING =
138                 CameraCharacteristics.LENS_FACING_FRONT;
139         public static final int CAMERA_DIRECTION_BACK_FACING =
140                 CameraCharacteristics.LENS_FACING_BACK;
141 
142         private int mCameraDirection = CAMERA_DIRECTION_UNKNOWN;
143 
144         /**
145          * Sets the camera direction. if camera direction is set to CAMERA_DIRECTION_UNKNOWN,
146          * the video state of the call should be used to infer the camera direction.
147          *
148          * @see {@link CameraCharacteristics#LENS_FACING_FRONT}
149          * @see {@link CameraCharacteristics#LENS_FACING_BACK}
150          */
setCameraDir(int cameraDirection)151         public void setCameraDir(int cameraDirection) {
152             if (cameraDirection == CAMERA_DIRECTION_FRONT_FACING
153                || cameraDirection == CAMERA_DIRECTION_BACK_FACING) {
154                 mCameraDirection = cameraDirection;
155             } else {
156                 mCameraDirection = CAMERA_DIRECTION_UNKNOWN;
157             }
158         }
159 
160         /**
161          * Gets the camera direction. if camera direction is set to CAMERA_DIRECTION_UNKNOWN,
162          * the video state of the call should be used to infer the camera direction.
163          *
164          * @see {@link CameraCharacteristics#LENS_FACING_FRONT}
165          * @see {@link CameraCharacteristics#LENS_FACING_BACK}
166          */
getCameraDir()167         public int getCameraDir() {
168             return mCameraDirection;
169         }
170 
toString()171         public String toString() {
172             return "(CameraDir:" + getCameraDir() + ")";
173         }
174     }
175 
176 
177     private static final String ID_PREFIX = Call.class.getSimpleName() + "_";
178     private static int sIdCounter = 0;
179 
180     private android.telecom.Call.Callback mTelecomCallCallback =
181             new android.telecom.Call.Callback() {
182                 @Override
183                 public void onStateChanged(android.telecom.Call call, int newState) {
184                     Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " newState="
185                             + newState);
186                     update();
187                 }
188 
189                 @Override
190                 public void onParentChanged(android.telecom.Call call,
191                         android.telecom.Call newParent) {
192                     Log.d(this, "TelecommCallCallback onParentChanged call=" + call + " newParent="
193                             + newParent);
194                     update();
195                 }
196 
197                 @Override
198                 public void onChildrenChanged(android.telecom.Call call,
199                         List<android.telecom.Call> children) {
200                     update();
201                 }
202 
203                 @Override
204                 public void onDetailsChanged(android.telecom.Call call,
205                         android.telecom.Call.Details details) {
206                     Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " details="
207                             + details);
208                     update();
209                 }
210 
211                 @Override
212                 public void onCannedTextResponsesLoaded(android.telecom.Call call,
213                         List<String> cannedTextResponses) {
214                     Log.d(this, "TelecommCallCallback onStateChanged call=" + call
215                             + " cannedTextResponses=" + cannedTextResponses);
216                     update();
217                 }
218 
219                 @Override
220                 public void onPostDialWait(android.telecom.Call call,
221                         String remainingPostDialSequence) {
222                     Log.d(this, "TelecommCallCallback onStateChanged call=" + call
223                             + " remainingPostDialSequence=" + remainingPostDialSequence);
224                     update();
225                 }
226 
227                 @Override
228                 public void onVideoCallChanged(android.telecom.Call call,
229                         VideoCall videoCall) {
230                     Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " videoCall="
231                             + videoCall);
232                     update();
233                 }
234 
235                 @Override
236                 public void onCallDestroyed(android.telecom.Call call) {
237                     Log.d(this, "TelecommCallCallback onStateChanged call=" + call);
238                     call.unregisterCallback(mTelecomCallCallback);
239                 }
240 
241                 @Override
242                 public void onConferenceableCallsChanged(android.telecom.Call call,
243                         List<android.telecom.Call> conferenceableCalls) {
244                     update();
245                 }
246             };
247 
248     private android.telecom.Call mTelecommCall;
249     private boolean mIsEmergencyCall;
250     private Uri mHandle;
251     private final String mId;
252     private int mState = State.INVALID;
253     private DisconnectCause mDisconnectCause;
254     private int mSessionModificationState;
255     private final List<String> mChildCallIds = new ArrayList<>();
256     private final VideoSettings mVideoSettings = new VideoSettings();
257     /**
258      * mModifyToVideoState is used to store requested upgrade / downgrade video state
259      */
260     private int mModifyToVideoState = VideoProfile.STATE_AUDIO_ONLY;
261 
262     private InCallVideoCallCallback mVideoCallCallback;
263     private String mChildNumber;
264     private String mLastForwardedNumber;
265     private String mCallSubject;
266     private PhoneAccountHandle mPhoneAccountHandle;
267 
268     /**
269      * Indicates whether the phone account associated with this call supports specifying a call
270      * subject.
271      */
272     private boolean mIsCallSubjectSupported;
273 
274     /**
275      * Used only to create mock calls for testing
276      */
277     @NeededForTesting
Call(int state)278     Call(int state) {
279         mTelecommCall = null;
280         mId = ID_PREFIX + Integer.toString(sIdCounter++);
281         setState(state);
282     }
283 
Call(android.telecom.Call telecommCall)284     public Call(android.telecom.Call telecommCall) {
285         mTelecommCall = telecommCall;
286         mId = ID_PREFIX + Integer.toString(sIdCounter++);
287 
288         updateFromTelecommCall();
289         mTelecommCall.registerCallback(mTelecomCallCallback);
290     }
291 
getTelecommCall()292     public android.telecom.Call getTelecommCall() {
293         return mTelecommCall;
294     }
295 
296     /**
297      * @return video settings of the call, null if the call is not a video call.
298      * @see VideoProfile
299      */
getVideoSettings()300     public VideoSettings getVideoSettings() {
301         return mVideoSettings;
302     }
303 
update()304     private void update() {
305         Trace.beginSection("Update");
306         int oldState = getState();
307         updateFromTelecommCall();
308         if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
309             CallList.getInstance().onDisconnect(this);
310         } else {
311             CallList.getInstance().onUpdate(this);
312         }
313         Trace.endSection();
314     }
315 
updateFromTelecommCall()316     private void updateFromTelecommCall() {
317         Log.d(this, "updateFromTelecommCall: " + mTelecommCall.toString());
318         setState(translateState(mTelecommCall.getState()));
319         setDisconnectCause(mTelecommCall.getDetails().getDisconnectCause());
320 
321         if (mTelecommCall.getVideoCall() != null) {
322             if (mVideoCallCallback == null) {
323                 mVideoCallCallback = new InCallVideoCallCallback(this);
324             }
325             mTelecommCall.getVideoCall().registerCallback(mVideoCallCallback);
326         }
327 
328         mChildCallIds.clear();
329         for (int i = 0; i < mTelecommCall.getChildren().size(); i++) {
330             mChildCallIds.add(
331                     CallList.getInstance().getCallByTelecommCall(
332                             mTelecommCall.getChildren().get(i)).getId());
333         }
334 
335         Bundle callExtras = mTelecommCall.getDetails().getExtras();
336         if (callExtras != null) {
337             // Check for a change in the child address and notify any listeners.
338             if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
339                 String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS);
340 
341                 if (!Objects.equals(childNumber, mChildNumber)) {
342                     mChildNumber = childNumber;
343                     CallList.getInstance().onChildNumberChange(this);
344                 }
345             }
346 
347             // Last forwarded number comes in as an array of strings.  We want to choose the last
348             // item in the array.  The forwarding numbers arrive independently of when the call is
349             // originally set up, so we need to notify the the UI of the change.
350             if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) {
351                 ArrayList<String> lastForwardedNumbers =
352                         callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER);
353 
354                 if (lastForwardedNumbers != null) {
355                     String lastForwardedNumber = null;
356                     if (!lastForwardedNumbers.isEmpty()) {
357                         lastForwardedNumber = lastForwardedNumbers.get(
358                                 lastForwardedNumbers.size() - 1);
359                     }
360 
361                     if (!Objects.equals(lastForwardedNumber, mLastForwardedNumber)) {
362                         mLastForwardedNumber = lastForwardedNumber;
363                         CallList.getInstance().onLastForwardedNumberChange(this);
364                     }
365                 }
366             }
367 
368             // Call subject is present in the extras at the start of call, so we do not need to
369             // notify any other listeners of this.
370             if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) {
371                 String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT);
372                 if (!Objects.equals(mCallSubject, callSubject)) {
373                     mCallSubject = callSubject;
374                 }
375             }
376         }
377 
378         // If the handle of the call has changed, update state for the call determining if it is an
379         // emergency call.
380         Uri newHandle = mTelecommCall.getDetails().getHandle();
381         if (!Objects.equals(mHandle, newHandle)) {
382             mHandle = newHandle;
383             updateEmergencyCallState();
384         }
385 
386         // If the phone account handle of the call is set, cache capability bit indicating whether
387         // the phone account supports call subjects.
388         PhoneAccountHandle newPhoneAccountHandle = mTelecommCall.getDetails().getAccountHandle();
389         if (!Objects.equals(mPhoneAccountHandle, newPhoneAccountHandle)) {
390             mPhoneAccountHandle = newPhoneAccountHandle;
391 
392             if (mPhoneAccountHandle != null) {
393                 TelecomManager mgr = InCallPresenter.getInstance().getTelecomManager();
394                 PhoneAccount phoneAccount = mgr.getPhoneAccount(mPhoneAccountHandle);
395                 if (phoneAccount != null) {
396                     mIsCallSubjectSupported = phoneAccount.hasCapabilities(
397                             PhoneAccount.CAPABILITY_CALL_SUBJECT);
398                 }
399             }
400         }
401     }
402 
translateState(int state)403     private static int translateState(int state) {
404         switch (state) {
405             case android.telecom.Call.STATE_NEW:
406             case android.telecom.Call.STATE_CONNECTING:
407                 return Call.State.CONNECTING;
408             case android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT:
409                 return Call.State.SELECT_PHONE_ACCOUNT;
410             case android.telecom.Call.STATE_DIALING:
411                 return Call.State.DIALING;
412             case android.telecom.Call.STATE_RINGING:
413                 return Call.State.INCOMING;
414             case android.telecom.Call.STATE_ACTIVE:
415                 return Call.State.ACTIVE;
416             case android.telecom.Call.STATE_HOLDING:
417                 return Call.State.ONHOLD;
418             case android.telecom.Call.STATE_DISCONNECTED:
419                 return Call.State.DISCONNECTED;
420             case android.telecom.Call.STATE_DISCONNECTING:
421                 return Call.State.DISCONNECTING;
422             default:
423                 return Call.State.INVALID;
424         }
425     }
426 
getId()427     public String getId() {
428         return mId;
429     }
430 
getNumber()431     public String getNumber() {
432         if (mTelecommCall == null) {
433             return null;
434         }
435         if (mTelecommCall.getDetails().getGatewayInfo() != null) {
436             return mTelecommCall.getDetails().getGatewayInfo()
437                     .getOriginalAddress().getSchemeSpecificPart();
438         }
439         return getHandle() == null ? null : getHandle().getSchemeSpecificPart();
440     }
441 
getHandle()442     public Uri getHandle() {
443         return mTelecommCall == null ? null : mTelecommCall.getDetails().getHandle();
444     }
445 
isEmergencyCall()446     public boolean isEmergencyCall() {
447         return mIsEmergencyCall;
448     }
449 
getState()450     public int getState() {
451         if (mTelecommCall != null && mTelecommCall.getParent() != null) {
452             return State.CONFERENCED;
453         } else {
454             return mState;
455         }
456     }
457 
setState(int state)458     public void setState(int state) {
459         mState = state;
460     }
461 
getNumberPresentation()462     public int getNumberPresentation() {
463         return mTelecommCall == null ? null : mTelecommCall.getDetails().getHandlePresentation();
464     }
465 
getCnapNamePresentation()466     public int getCnapNamePresentation() {
467         return mTelecommCall == null ? null
468                 : mTelecommCall.getDetails().getCallerDisplayNamePresentation();
469     }
470 
getCnapName()471     public String getCnapName() {
472         return mTelecommCall == null ? null
473                 : getTelecommCall().getDetails().getCallerDisplayName();
474     }
475 
getIntentExtras()476     public Bundle getIntentExtras() {
477         return mTelecommCall == null ? null : mTelecommCall.getDetails().getIntentExtras();
478     }
479 
getExtras()480     public Bundle getExtras() {
481         return mTelecommCall == null ? null : mTelecommCall.getDetails().getExtras();
482     }
483 
484     /**
485      * @return The child number for the call, or {@code null} if none specified.
486      */
getChildNumber()487     public String getChildNumber() {
488         return mChildNumber;
489     }
490 
491     /**
492      * @return The last forwarded number for the call, or {@code null} if none specified.
493      */
getLastForwardedNumber()494     public String getLastForwardedNumber() {
495         return mLastForwardedNumber;
496     }
497 
498     /**
499      * @return The call subject, or {@code null} if none specified.
500      */
getCallSubject()501     public String getCallSubject() {
502         return mCallSubject;
503     }
504 
505     /**
506      * @return {@code true} if the call's phone account supports call subjects, {@code false}
507      *      otherwise.
508      */
isCallSubjectSupported()509     public boolean isCallSubjectSupported() {
510         return mIsCallSubjectSupported;
511     }
512 
513     /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
getDisconnectCause()514     public DisconnectCause getDisconnectCause() {
515         if (mState == State.DISCONNECTED || mState == State.IDLE) {
516             return mDisconnectCause;
517         }
518 
519         return new DisconnectCause(DisconnectCause.UNKNOWN);
520     }
521 
setDisconnectCause(DisconnectCause disconnectCause)522     public void setDisconnectCause(DisconnectCause disconnectCause) {
523         mDisconnectCause = disconnectCause;
524     }
525 
526     /** Returns the possible text message responses. */
getCannedSmsResponses()527     public List<String> getCannedSmsResponses() {
528         return mTelecommCall.getCannedTextResponses();
529     }
530 
531     /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
can(int capabilities)532     public boolean can(int capabilities) {
533         int supportedCapabilities = mTelecommCall.getDetails().getCallCapabilities();
534 
535         if ((capabilities & android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
536             // We allow you to merge if the capabilities allow it or if it is a call with
537             // conferenceable calls.
538             if (mTelecommCall.getConferenceableCalls().isEmpty() &&
539                 ((android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE
540                         & supportedCapabilities) == 0)) {
541                 // Cannot merge calls if there are no calls to merge with.
542                 return false;
543             }
544             capabilities &= ~android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE;
545         }
546         return (capabilities == (capabilities & mTelecommCall.getDetails().getCallCapabilities()));
547     }
548 
hasProperty(int property)549     public boolean hasProperty(int property) {
550         return mTelecommCall.getDetails().hasProperty(property);
551     }
552 
553     /** Gets the time when the call first became active. */
getConnectTimeMillis()554     public long getConnectTimeMillis() {
555         return mTelecommCall.getDetails().getConnectTimeMillis();
556     }
557 
isConferenceCall()558     public boolean isConferenceCall() {
559         return mTelecommCall.getDetails().hasProperty(
560                 android.telecom.Call.Details.PROPERTY_CONFERENCE);
561     }
562 
getGatewayInfo()563     public GatewayInfo getGatewayInfo() {
564         return mTelecommCall == null ? null : mTelecommCall.getDetails().getGatewayInfo();
565     }
566 
getAccountHandle()567     public PhoneAccountHandle getAccountHandle() {
568         return mTelecommCall == null ? null : mTelecommCall.getDetails().getAccountHandle();
569     }
570 
getVideoCall()571     public VideoCall getVideoCall() {
572         return mTelecommCall == null ? null : mTelecommCall.getVideoCall();
573     }
574 
getChildCallIds()575     public List<String> getChildCallIds() {
576         return mChildCallIds;
577     }
578 
getParentId()579     public String getParentId() {
580         android.telecom.Call parentCall = mTelecommCall.getParent();
581         if (parentCall != null) {
582             return CallList.getInstance().getCallByTelecommCall(parentCall).getId();
583         }
584         return null;
585     }
586 
getVideoState()587     public int getVideoState() {
588         return mTelecommCall.getDetails().getVideoState();
589     }
590 
isVideoCall(Context context)591     public boolean isVideoCall(Context context) {
592         return CallUtil.isVideoEnabled(context) &&
593                 CallUtils.isVideoCall(getVideoState());
594     }
595 
596     /**
597      * This method is called when we request for a video upgrade or downgrade. This handles the
598      * session modification state RECEIVED_UPGRADE_TO_VIDEO_REQUEST and sets the video state we
599      * want to upgrade/downgrade to.
600      */
setSessionModificationTo(int videoState)601     public void setSessionModificationTo(int videoState) {
602         Log.d(this, "setSessionModificationTo - video state= " + videoState);
603         if (videoState == getVideoState()) {
604             mSessionModificationState = Call.SessionModificationState.NO_REQUEST;
605             Log.w(this,"setSessionModificationTo - Clearing session modification state");
606         } else {
607             mSessionModificationState =
608                 Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
609             setModifyToVideoState(videoState);
610             CallList.getInstance().onUpgradeToVideo(this);
611         }
612 
613         Log.d(this, "setSessionModificationTo - mSessionModificationState="
614             + mSessionModificationState + " video state= " + videoState);
615         update();
616     }
617 
618     /**
619      * This method is called to handle any other session modification states other than
620      * RECEIVED_UPGRADE_TO_VIDEO_REQUEST. We set the modification state and reset the video state
621      * when an upgrade request has been completed or failed.
622      */
setSessionModificationState(int state)623     public void setSessionModificationState(int state) {
624         if (state == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
625             Log.e(this,
626                     "setSessionModificationState not valid for RECEIVED_UPGRADE_TO_VIDEO_REQUEST");
627             return;
628         }
629 
630         boolean hasChanged = mSessionModificationState != state;
631         mSessionModificationState = state;
632         Log.d(this, "setSessionModificationState " + state + " mSessionModificationState="
633                 + mSessionModificationState);
634         if (hasChanged) {
635             CallList.getInstance().onSessionModificationStateChange(this, state);
636         }
637     }
638 
639     /**
640      * Determines if the call handle is an emergency number or not and caches the result to avoid
641      * repeated calls to isEmergencyNumber.
642      */
updateEmergencyCallState()643     private void updateEmergencyCallState() {
644         Uri handle = mTelecommCall.getDetails().getHandle();
645         mIsEmergencyCall = PhoneNumberUtils.isEmergencyNumber(
646                 handle == null ? "" : handle.getSchemeSpecificPart());
647     }
648 
setModifyToVideoState(int newVideoState)649     private void setModifyToVideoState(int newVideoState) {
650         mModifyToVideoState = newVideoState;
651     }
652 
getModifyToVideoState()653     public int getModifyToVideoState() {
654         return mModifyToVideoState;
655     }
656 
areSame(Call call1, Call call2)657     public static boolean areSame(Call call1, Call call2) {
658         if (call1 == null && call2 == null) {
659             return true;
660         } else if (call1 == null || call2 == null) {
661             return false;
662         }
663 
664         // otherwise compare call Ids
665         return call1.getId().equals(call2.getId());
666     }
667 
areSameNumber(Call call1, Call call2)668     public static boolean areSameNumber(Call call1, Call call2) {
669         if (call1 == null && call2 == null) {
670             return true;
671         } else if (call1 == null || call2 == null) {
672             return false;
673         }
674 
675         // otherwise compare call Numbers
676         return TextUtils.equals(call1.getNumber(), call2.getNumber());
677     }
678 
getSessionModificationState()679     public int getSessionModificationState() {
680         return mSessionModificationState;
681     }
682 
683     @Override
toString()684     public String toString() {
685         if (mTelecommCall == null) {
686             // This should happen only in testing since otherwise we would never have a null
687             // Telecom call.
688             return String.valueOf(mId);
689         }
690 
691         return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s, conferenceable:%s, " +
692                 "videoState:%s, mSessionModificationState:%d, VideoSettings:%s]",
693                 mId,
694                 State.toString(getState()),
695                 android.telecom.Call.Details
696                         .capabilitiesToString(mTelecommCall.getDetails().getCallCapabilities()),
697                 mChildCallIds,
698                 getParentId(),
699                 this.mTelecommCall.getConferenceableCalls(),
700                 VideoProfile.videoStateToString(mTelecommCall.getDetails().getVideoState()),
701                 mSessionModificationState,
702                 getVideoSettings());
703     }
704 
toSimpleString()705     public String toSimpleString() {
706         return super.toString();
707     }
708 }
709