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