• 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 
21 import android.content.Context;
22 import android.net.Uri;
23 import android.telecom.CallProperties;
24 import android.telecom.DisconnectCause;
25 import android.telecom.PhoneCapabilities;
26 import android.telecom.GatewayInfo;
27 import android.telecom.InCallService.VideoCall;
28 import android.telecom.PhoneAccountHandle;
29 import android.telecom.VideoProfile;
30 
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Locale;
34 
35 /**
36  * Describes a single call and its state.
37  */
38 public final class Call {
39     /* Defines different states of this call */
40     public static class State {
41         public static final int INVALID = 0;
42         public static final int IDLE = 1;           /* The call is idle.  Nothing active */
43         public static final int ACTIVE = 2;         /* There is an active call */
44         public static final int INCOMING = 3;       /* A normal incoming phone call */
45         public static final int CALL_WAITING = 4;   /* Incoming call while another is active */
46         public static final int DIALING = 5;        /* An outgoing call during dial phase */
47         public static final int REDIALING = 6;      /* Subsequent dialing attempt after a failure */
48         public static final int ONHOLD = 7;         /* An active phone call placed on hold */
49         public static final int DISCONNECTING = 8;  /* A call is being ended. */
50         public static final int DISCONNECTED = 9;   /* State after a call disconnects */
51         public static final int CONFERENCED = 10;   /* Call part of a conference call */
52         public static final int PRE_DIAL_WAIT = 11; /* Waiting for user before outgoing call */
53         public static final int CONNECTING = 12;    /* Waiting for Telecomm broadcast to finish */
54 
isConnectingOrConnected(int state)55         public static boolean isConnectingOrConnected(int state) {
56             switch(state) {
57                 case ACTIVE:
58                 case INCOMING:
59                 case CALL_WAITING:
60                 case CONNECTING:
61                 case DIALING:
62                 case REDIALING:
63                 case ONHOLD:
64                 case CONFERENCED:
65                     return true;
66                 default:
67             }
68             return false;
69         }
70 
isDialing(int state)71         public static boolean isDialing(int state) {
72             return state == DIALING || state == REDIALING;
73         }
74 
toString(int state)75         public static String toString(int state) {
76             switch (state) {
77                 case INVALID:
78                     return "INVALID";
79                 case IDLE:
80                     return "IDLE";
81                 case ACTIVE:
82                     return "ACTIVE";
83                 case INCOMING:
84                     return "INCOMING";
85                 case CALL_WAITING:
86                     return "CALL_WAITING";
87                 case DIALING:
88                     return "DIALING";
89                 case REDIALING:
90                     return "REDIALING";
91                 case ONHOLD:
92                     return "ONHOLD";
93                 case DISCONNECTING:
94                     return "DISCONNECTING";
95                 case DISCONNECTED:
96                     return "DISCONNECTED";
97                 case CONFERENCED:
98                     return "CONFERENCED";
99                 case PRE_DIAL_WAIT:
100                     return "PRE_DIAL_WAIT";
101                 case CONNECTING:
102                     return "CONNECTING";
103                 default:
104                     return "UNKNOWN";
105             }
106         }
107     }
108 
109     /**
110      * Defines different states of session modify requests, which are used to upgrade to video, or
111      * downgrade to audio.
112      */
113     public static class SessionModificationState {
114         public static final int NO_REQUEST = 0;
115         public static final int WAITING_FOR_RESPONSE = 1;
116         public static final int REQUEST_FAILED = 2;
117         public static final int RECEIVED_UPGRADE_TO_VIDEO_REQUEST = 3;
118     }
119 
120     private static final String ID_PREFIX = Call.class.getSimpleName() + "_";
121     private static int sIdCounter = 0;
122 
123     private android.telecom.Call.Listener mTelecommCallListener =
124             new android.telecom.Call.Listener() {
125                 @Override
126                 public void onStateChanged(android.telecom.Call call, int newState) {
127                     update();
128                 }
129 
130                 @Override
131                 public void onParentChanged(android.telecom.Call call,
132                         android.telecom.Call newParent) {
133                     update();
134                 }
135 
136                 @Override
137                 public void onChildrenChanged(android.telecom.Call call,
138                         List<android.telecom.Call> children) {
139                     update();
140                 }
141 
142                 @Override
143                 public void onDetailsChanged(android.telecom.Call call,
144                         android.telecom.Call.Details details) {
145                     update();
146                 }
147 
148                 @Override
149                 public void onCannedTextResponsesLoaded(android.telecom.Call call,
150                         List<String> cannedTextResponses) {
151                     update();
152                 }
153 
154                 @Override
155                 public void onPostDialWait(android.telecom.Call call,
156                         String remainingPostDialSequence) {
157                     update();
158                 }
159 
160                 @Override
161                 public void onVideoCallChanged(android.telecom.Call call,
162                         VideoCall videoCall) {
163                     update();
164                 }
165 
166                 @Override
167                 public void onCallDestroyed(android.telecom.Call call) {
168                     call.removeListener(mTelecommCallListener);
169                 }
170 
171                 @Override
172                 public void onConferenceableCallsChanged(android.telecom.Call call,
173                         List<android.telecom.Call> conferenceableCalls) {
174                     update();
175                 }
176             };
177 
178     private final android.telecom.Call mTelecommCall;
179     private final String mId;
180     private int mState = State.INVALID;
181     private DisconnectCause mDisconnectCause;
182     private int mSessionModificationState;
183     private final List<String> mChildCallIds = new ArrayList<>();
184 
185     private InCallVideoCallListener mVideoCallListener;
186 
Call(android.telecom.Call telecommCall)187     public Call(android.telecom.Call telecommCall) {
188         mTelecommCall = telecommCall;
189         mId = ID_PREFIX + Integer.toString(sIdCounter++);
190         updateFromTelecommCall();
191         mTelecommCall.addListener(mTelecommCallListener);
192     }
193 
getTelecommCall()194     public android.telecom.Call getTelecommCall() {
195         return mTelecommCall;
196     }
197 
update()198     private void update() {
199         int oldState = getState();
200         updateFromTelecommCall();
201         if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
202             CallList.getInstance().onDisconnect(this);
203         } else {
204             CallList.getInstance().onUpdate(this);
205         }
206     }
207 
updateFromTelecommCall()208     private void updateFromTelecommCall() {
209         Log.d(this, "updateFromTelecommCall: " + mTelecommCall);
210         setState(translateState(mTelecommCall.getState()));
211         setDisconnectCause(mTelecommCall.getDetails().getDisconnectCause());
212 
213         if (mTelecommCall.getVideoCall() != null) {
214             if (mVideoCallListener == null) {
215                 mVideoCallListener = new InCallVideoCallListener(this);
216             }
217             mTelecommCall.getVideoCall().setVideoCallListener(mVideoCallListener);
218         }
219 
220         mChildCallIds.clear();
221         for (int i = 0; i < mTelecommCall.getChildren().size(); i++) {
222             mChildCallIds.add(
223                     CallList.getInstance().getCallByTelecommCall(
224                             mTelecommCall.getChildren().get(i)).getId());
225         }
226     }
227 
translateState(int state)228     private static int translateState(int state) {
229         switch (state) {
230             case android.telecom.Call.STATE_CONNECTING:
231                 return Call.State.CONNECTING;
232             case android.telecom.Call.STATE_PRE_DIAL_WAIT:
233                 return Call.State.PRE_DIAL_WAIT;
234             case android.telecom.Call.STATE_DIALING:
235             case android.telecom.Call.STATE_NEW:
236                 return Call.State.DIALING;
237             case android.telecom.Call.STATE_RINGING:
238                 return Call.State.INCOMING;
239             case android.telecom.Call.STATE_ACTIVE:
240                 return Call.State.ACTIVE;
241             case android.telecom.Call.STATE_HOLDING:
242                 return Call.State.ONHOLD;
243             case android.telecom.Call.STATE_DISCONNECTED:
244                 return Call.State.DISCONNECTED;
245             case android.telecom.Call.STATE_DISCONNECTING:
246                 return Call.State.DISCONNECTING;
247             default:
248                 return Call.State.INVALID;
249         }
250     }
251 
getId()252     public String getId() {
253         return mId;
254     }
255 
getNumber()256     public String getNumber() {
257         if (mTelecommCall.getDetails().getGatewayInfo() != null) {
258             return mTelecommCall.getDetails().getGatewayInfo()
259                     .getOriginalAddress().getSchemeSpecificPart();
260         }
261         return getHandle() == null ? null : getHandle().getSchemeSpecificPart();
262     }
263 
getHandle()264     public Uri getHandle() {
265         return mTelecommCall.getDetails().getHandle();
266     }
267 
getState()268     public int getState() {
269         if (mTelecommCall.getParent() != null) {
270             return State.CONFERENCED;
271         } else {
272             return mState;
273         }
274     }
275 
setState(int state)276     public void setState(int state) {
277         mState = state;
278     }
279 
getNumberPresentation()280     public int getNumberPresentation() {
281         return getTelecommCall().getDetails().getHandlePresentation();
282     }
283 
getCnapNamePresentation()284     public int getCnapNamePresentation() {
285         return getTelecommCall().getDetails().getCallerDisplayNamePresentation();
286     }
287 
getCnapName()288     public String getCnapName() {
289         return getTelecommCall().getDetails().getCallerDisplayName();
290     }
291 
292     /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
getDisconnectCause()293     public DisconnectCause getDisconnectCause() {
294         if (mState == State.DISCONNECTED || mState == State.IDLE) {
295             return mDisconnectCause;
296         }
297 
298         return new DisconnectCause(DisconnectCause.UNKNOWN);
299     }
300 
setDisconnectCause(DisconnectCause disconnectCause)301     public void setDisconnectCause(DisconnectCause disconnectCause) {
302         mDisconnectCause = disconnectCause;
303     }
304 
305     /** Returns the possible text message responses. */
getCannedSmsResponses()306     public List<String> getCannedSmsResponses() {
307         return mTelecommCall.getCannedTextResponses();
308     }
309 
310     /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
can(int capabilities)311     public boolean can(int capabilities) {
312         int supportedCapabilities = mTelecommCall.getDetails().getCallCapabilities();
313 
314         if ((capabilities & PhoneCapabilities.MERGE_CONFERENCE) != 0) {
315             // We allow you to merge if the capabilities allow it or if it is a call with
316             // conferenceable calls.
317             if (mTelecommCall.getConferenceableCalls().isEmpty() &&
318                     ((PhoneCapabilities.MERGE_CONFERENCE & supportedCapabilities) == 0)) {
319                 // Cannot merge calls if there are no calls to merge with.
320                 return false;
321             }
322             capabilities &= ~PhoneCapabilities.MERGE_CONFERENCE;
323         }
324         return (capabilities == (capabilities & mTelecommCall.getDetails().getCallCapabilities()));
325     }
326 
hasProperty(int property)327     private boolean hasProperty(int property) {
328         return property == (property & mTelecommCall.getDetails().getCallProperties());
329     }
330 
331     /** Gets the time when the call first became active. */
getConnectTimeMillis()332     public long getConnectTimeMillis() {
333         return mTelecommCall.getDetails().getConnectTimeMillis();
334     }
335 
isConferenceCall()336     public boolean isConferenceCall() {
337         return hasProperty(CallProperties.CONFERENCE);
338     }
339 
getGatewayInfo()340     public GatewayInfo getGatewayInfo() {
341         return mTelecommCall.getDetails().getGatewayInfo();
342     }
343 
getAccountHandle()344     public PhoneAccountHandle getAccountHandle() {
345         return mTelecommCall.getDetails().getAccountHandle();
346     }
347 
getVideoCall()348     public VideoCall getVideoCall() {
349         return mTelecommCall.getVideoCall();
350     }
351 
getChildCallIds()352     public List<String> getChildCallIds() {
353         return mChildCallIds;
354     }
355 
getParentId()356     public String getParentId() {
357         android.telecom.Call parentCall = mTelecommCall.getParent();
358         if (parentCall != null) {
359             return CallList.getInstance().getCallByTelecommCall(parentCall).getId();
360         }
361         return null;
362     }
363 
getVideoState()364     public int getVideoState() {
365         return mTelecommCall.getDetails().getVideoState();
366     }
367 
isVideoCall(Context context)368     public boolean isVideoCall(Context context) {
369         return CallUtil.isVideoEnabled(context) &&
370                 VideoProfile.VideoState.isBidirectional(getVideoState());
371     }
372 
setSessionModificationState(int state)373     public void setSessionModificationState(int state) {
374         boolean hasChanged = mSessionModificationState != state;
375         mSessionModificationState = state;
376 
377         if (hasChanged) {
378             update();
379         }
380     }
381 
areSame(Call call1, Call call2)382     public static boolean areSame(Call call1, Call call2) {
383         if (call1 == null && call2 == null) {
384             return true;
385         } else if (call1 == null || call2 == null) {
386             return false;
387         }
388 
389         // otherwise compare call Ids
390         return call1.getId().equals(call2.getId());
391     }
392 
getSessionModificationState()393     public int getSessionModificationState() {
394         return mSessionModificationState;
395     }
396 
397     @Override
toString()398     public String toString() {
399         return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s, videoState:%d]",
400                 mId,
401                 State.toString(getState()),
402                 PhoneCapabilities.toString(mTelecommCall.getDetails().getCallCapabilities()),
403                 mChildCallIds,
404                 getParentId(),
405                 mTelecommCall.getDetails().getVideoState());
406     }
407 }
408