blob: 1d33b3bca11e06f2a5cc862dff04307cf0283255 [file] [log] [blame]
Ihab Awade63fadb2014-07-09 21:52:04 -07001/*
2 * Copyright (C) 2014 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
Tyler Gunnef9f6f92014-09-12 22:16:17 -070017package android.telecom;
Ihab Awade63fadb2014-07-09 21:52:04 -070018
Gabriel Pealb95f1692014-08-19 14:24:18 -070019import android.annotation.SystemApi;
Ihab Awade63fadb2014-07-09 21:52:04 -070020import android.net.Uri;
Nancy Chen10798dc2014-08-08 14:00:25 -070021import android.os.Bundle;
Ihab Awade63fadb2014-07-09 21:52:04 -070022import android.telephony.DisconnectCause;
23
Andrew Lee50aca232014-07-22 16:41:54 -070024import java.lang.String;
Ihab Awade63fadb2014-07-09 21:52:04 -070025import java.util.ArrayList;
26import java.util.Collections;
27import java.util.List;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070028import java.util.Map;
Ihab Awade63fadb2014-07-09 21:52:04 -070029import java.util.Objects;
Jay Shrauner229e3822014-08-15 09:23:07 -070030import java.util.concurrent.CopyOnWriteArrayList;
Ihab Awade63fadb2014-07-09 21:52:04 -070031
32/**
33 * Represents an ongoing phone call that the in-call app should present to the user.
Ihab Awadb19a0bc2014-08-07 19:46:01 -070034 *
35 * {@hide}
Ihab Awade63fadb2014-07-09 21:52:04 -070036 */
Gabriel Pealb95f1692014-08-19 14:24:18 -070037@SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -070038public final class Call {
39 /**
40 * The state of a {@code Call} when newly created.
41 */
42 public static final int STATE_NEW = 0;
43
44 /**
45 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
46 */
47 public static final int STATE_DIALING = 1;
48
49 /**
50 * The state of an incoming {@code Call} when ringing locally, but not yet connected.
51 */
52 public static final int STATE_RINGING = 2;
53
54 /**
55 * The state of a {@code Call} when in a holding state.
56 */
57 public static final int STATE_HOLDING = 3;
58
59 /**
60 * The state of a {@code Call} when actively supporting conversation.
61 */
62 public static final int STATE_ACTIVE = 4;
63
64 /**
65 * The state of a {@code Call} when no further voice or other communication is being
66 * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
67 * is no longer active, and the local data transport has or inevitably will release resources
68 * associated with this {@code Call}.
69 */
70 public static final int STATE_DISCONNECTED = 7;
71
Nancy Chen5da0fd52014-07-08 14:16:17 -070072 /**
73 * The state of an outgoing {@code Call}, but waiting for user input before proceeding.
74 */
75 public static final int STATE_PRE_DIAL_WAIT = 8;
76
Nancy Chene20930f2014-08-07 16:17:21 -070077 /**
Nancy Chene9b7a8e2014-08-08 14:26:27 -070078 * The initial state of an outgoing {@code Call}.
79 * Common transitions are to {@link #STATE_DIALING} state for a successful call or
80 * {@link #STATE_DISCONNECTED} if it failed.
Nancy Chene20930f2014-08-07 16:17:21 -070081 */
82 public static final int STATE_CONNECTING = 9;
83
Ihab Awade63fadb2014-07-09 21:52:04 -070084 public static class Details {
85 private final Uri mHandle;
86 private final int mHandlePresentation;
87 private final String mCallerDisplayName;
88 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -070089 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -070090 private final int mCallCapabilities;
Andrew Lee223ad142014-08-27 16:33:08 -070091 private final int mCallProperties;
Ihab Awade63fadb2014-07-09 21:52:04 -070092 private final int mDisconnectCauseCode;
Ihab Awadb19a0bc2014-08-07 19:46:01 -070093 private final String mDisconnectCauseMessage;
Ihab Awade63fadb2014-07-09 21:52:04 -070094 private final long mConnectTimeMillis;
95 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -070096 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -070097 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -070098 private final Bundle mExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -070099
100 /**
101 * @return The handle (e.g., phone number) to which the {@code Call} is currently
102 * connected.
103 */
104 public Uri getHandle() {
105 return mHandle;
106 }
107
108 /**
109 * @return The presentation requirements for the handle. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700110 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700111 */
112 public int getHandlePresentation() {
113 return mHandlePresentation;
114 }
115
116 /**
117 * @return The display name for the caller.
118 */
119 public String getCallerDisplayName() {
120 return mCallerDisplayName;
121 }
122
123 /**
124 * @return The presentation requirements for the caller display name. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700125 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700126 */
127 public int getCallerDisplayNamePresentation() {
128 return mCallerDisplayNamePresentation;
129 }
130
131 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700132 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
133 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700134 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700135 public PhoneAccountHandle getAccountHandle() {
136 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700137 }
138
139 /**
140 * @return A bitmask of the capabilities of the {@code Call}, as defined in
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700141 * {@link PhoneCapabilities}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700142 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700143 public int getCallCapabilities() {
144 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700145 }
146
147 /**
Andrew Lee223ad142014-08-27 16:33:08 -0700148 * @return A bitmask of the properties of the {@code Call}, as defined in
149 * {@link CallProperties}.
150 */
151 public int getCallProperties() {
152 return mCallProperties;
153 }
154
155 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700156 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
157 * as a code chosen from among those declared in {@link DisconnectCause}.
158 */
159 public int getDisconnectCauseCode() {
160 return mDisconnectCauseCode;
161 }
162
163 /**
164 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, an optional reason for
165 * disconnection expressed as a free text message.
166 */
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700167 public String getDisconnectCauseMessage() {
168 return mDisconnectCauseMessage;
Ihab Awade63fadb2014-07-09 21:52:04 -0700169 }
170
171 /**
172 * @return The time the {@code Call} has been connected. This information is updated
173 * periodically, but user interfaces should not rely on this to display any "call time
174 * clock".
175 */
176 public long getConnectTimeMillis() {
177 return mConnectTimeMillis;
178 }
179
180 /**
181 * @return Information about any calling gateway the {@code Call} may be using.
182 */
183 public GatewayInfo getGatewayInfo() {
184 return mGatewayInfo;
185 }
186
Andrew Lee7a341382014-07-15 17:05:08 -0700187 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700188 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700189 */
190 public int getVideoState() {
191 return mVideoState;
192 }
193
Ihab Awad5d0410f2014-07-30 10:07:40 -0700194 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700195 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
Ihab Awad5d0410f2014-07-30 10:07:40 -0700196 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700197 */
198 public StatusHints getStatusHints() {
199 return mStatusHints;
200 }
201
Nancy Chen10798dc2014-08-08 14:00:25 -0700202 /**
203 * @return A bundle extras to pass with the call
204 */
205 public Bundle getExtras() {
206 return mExtras;
207 }
208
Ihab Awade63fadb2014-07-09 21:52:04 -0700209 @Override
210 public boolean equals(Object o) {
211 if (o instanceof Details) {
212 Details d = (Details) o;
213 return
214 Objects.equals(mHandle, d.mHandle) &&
215 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
216 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
217 Objects.equals(mCallerDisplayNamePresentation,
218 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700219 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700220 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Andrew Lee223ad142014-08-27 16:33:08 -0700221 Objects.equals(mCallProperties, d.mCallProperties) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700222 Objects.equals(mDisconnectCauseCode, d.mDisconnectCauseCode) &&
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700223 Objects.equals(mDisconnectCauseMessage, d.mDisconnectCauseMessage) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700224 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700225 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700226 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700227 Objects.equals(mStatusHints, d.mStatusHints) &&
228 Objects.equals(mExtras, d.mExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700229 }
230 return false;
231 }
232
233 @Override
234 public int hashCode() {
235 return
236 Objects.hashCode(mHandle) +
237 Objects.hashCode(mHandlePresentation) +
238 Objects.hashCode(mCallerDisplayName) +
239 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700240 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700241 Objects.hashCode(mCallCapabilities) +
Andrew Lee223ad142014-08-27 16:33:08 -0700242 Objects.hashCode(mCallProperties) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700243 Objects.hashCode(mDisconnectCauseCode) +
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700244 Objects.hashCode(mDisconnectCauseMessage) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700245 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700246 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700247 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700248 Objects.hashCode(mStatusHints) +
249 Objects.hashCode(mExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700250 }
251
252 /** {@hide} */
253 public Details(
254 Uri handle,
255 int handlePresentation,
256 String callerDisplayName,
257 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700258 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700259 int capabilities,
Andrew Lee223ad142014-08-27 16:33:08 -0700260 int properties,
Ihab Awade63fadb2014-07-09 21:52:04 -0700261 int disconnectCauseCode,
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700262 String disconnectCauseMessage,
Ihab Awade63fadb2014-07-09 21:52:04 -0700263 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700264 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700265 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700266 StatusHints statusHints,
267 Bundle extras) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700268 mHandle = handle;
269 mHandlePresentation = handlePresentation;
270 mCallerDisplayName = callerDisplayName;
271 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700272 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700273 mCallCapabilities = capabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700274 mCallProperties = properties;
Ihab Awade63fadb2014-07-09 21:52:04 -0700275 mDisconnectCauseCode = disconnectCauseCode;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700276 mDisconnectCauseMessage = disconnectCauseMessage;
Ihab Awade63fadb2014-07-09 21:52:04 -0700277 mConnectTimeMillis = connectTimeMillis;
278 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700279 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700280 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700281 mExtras = extras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700282 }
283 }
284
285 public static abstract class Listener {
286 /**
287 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
288 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700289 * @param call The {@code Call} invoking this method.
290 * @param state The new state of the {@code Call}.
291 */
292 public void onStateChanged(Call call, int state) {}
293
294 /**
295 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
296 *
297 * @param call The {@code Call} invoking this method.
298 * @param parent The new parent of the {@code Call}.
299 */
300 public void onParentChanged(Call call, Call parent) {}
301
302 /**
303 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
304 *
305 * @param call The {@code Call} invoking this method.
306 * @param children The new children of the {@code Call}.
307 */
308 public void onChildrenChanged(Call call, List<Call> children) {}
309
310 /**
311 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
312 *
313 * @param call The {@code Call} invoking this method.
314 * @param details A {@code Details} object describing the {@code Call}.
315 */
316 public void onDetailsChanged(Call call, Details details) {}
317
318 /**
319 * Invoked when the text messages that can be used as responses to the incoming
320 * {@code Call} are loaded from the relevant database.
321 * See {@link #getCannedTextResponses()}.
322 *
323 * @param call The {@code Call} invoking this method.
324 * @param cannedTextResponses The text messages useable as responses.
325 */
326 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
327
328 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700329 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
330 * character. This causes the post-dial signals to stop pending user confirmation. An
331 * implementation should present this choice to the user and invoke
332 * {@link #postDialContinue(boolean)} when the user makes the choice.
333 *
334 * @param call The {@code Call} invoking this method.
335 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
336 */
337 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
338
339 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700340 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700341 *
342 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700343 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Tyler Gunn75537ae2014-08-22 11:33:13 -0700344 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700345 */
Andrew Lee50aca232014-07-22 16:41:54 -0700346 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700347
348 /**
349 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
350 * up their UI for the {@code Call} in response to state transitions. Specifically,
351 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
352 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
353 * clients should wait for this method to be invoked.
354 *
355 * @param call The {@code Call} being destroyed.
356 */
357 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700358
359 /**
360 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
361 * conferenced.
362 *
363 * @param call The {@code Call} being updated.
364 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
365 * conferenced.
366 */
367 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700368 }
369
370 private final Phone mPhone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700371 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700372 private final InCallAdapter mInCallAdapter;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700373 private final List<String> mChildrenIds = new ArrayList<>();
Ihab Awade63fadb2014-07-09 21:52:04 -0700374 private final List<Call> mChildren = new ArrayList<>();
375 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Jay Shrauner229e3822014-08-15 09:23:07 -0700376 private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700377 private final List<Call> mConferenceableCalls = new ArrayList<>();
378 private final List<Call> mUnmodifiableConferenceableCalls =
379 Collections.unmodifiableList(mConferenceableCalls);
380
Santos Cordon823fd3c2014-08-07 18:35:18 -0700381 private boolean mChildrenCached;
382 private String mParentId = null;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700383 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -0700384 private List<String> mCannedTextResponses = null;
385 private String mRemainingPostDialSequence;
Andrew Lee50aca232014-07-22 16:41:54 -0700386 private InCallService.VideoCall mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700387 private Details mDetails;
Ihab Awade63fadb2014-07-09 21:52:04 -0700388
389 /**
390 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
391 *
392 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
393 * remaining or this {@code Call} is not in a post-dial state.
394 */
395 public String getRemainingPostDialSequence() {
396 return mRemainingPostDialSequence;
397 }
398
399 /**
400 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700401 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -0700402 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700403 public void answer(int videoState) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700404 mInCallAdapter.answerCall(mTelecomCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700405 }
406
407 /**
408 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
409 *
410 * @param rejectWithMessage Whether to reject with a text message.
411 * @param textMessage An optional text message with which to respond.
412 */
413 public void reject(boolean rejectWithMessage, String textMessage) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700414 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
Ihab Awade63fadb2014-07-09 21:52:04 -0700415 }
416
417 /**
418 * Instructs this {@code Call} to disconnect.
419 */
420 public void disconnect() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700421 mInCallAdapter.disconnectCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700422 }
423
424 /**
425 * Instructs this {@code Call} to go on hold.
426 */
427 public void hold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700428 mInCallAdapter.holdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700429 }
430
431 /**
432 * Instructs this {@link #STATE_HOLDING} call to release from hold.
433 */
434 public void unhold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700435 mInCallAdapter.unholdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700436 }
437
438 /**
439 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
440 *
441 * Any other currently playing DTMF tone in the specified call is immediately stopped.
442 *
443 * @param digit A character representing the DTMF digit for which to play the tone. This
444 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
445 */
446 public void playDtmfTone(char digit) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700447 mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
Ihab Awade63fadb2014-07-09 21:52:04 -0700448 }
449
450 /**
451 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
452 * currently playing.
453 *
454 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
455 * currently playing, this method will do nothing.
456 */
457 public void stopDtmfTone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700458 mInCallAdapter.stopDtmfTone(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700459 }
460
461 /**
462 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
463 *
464 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
465 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -0700466 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700467 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700468 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
469 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700470 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700471 * {@code Call} will pause playing the tones and notify listeners via
472 * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app
473 * should display to the user an indication of this state and an affordance to continue
474 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
475 * app should invoke the {@link #postDialContinue(boolean)} method.
476 *
477 * @param proceed Whether or not to continue with the post-dial sequence.
478 */
479 public void postDialContinue(boolean proceed) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700480 mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
Ihab Awade63fadb2014-07-09 21:52:04 -0700481 }
482
483 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -0700484 * Notifies this {@code Call} that an account has been selected and to proceed with placing
485 * an outgoing call.
Nancy Chen5da0fd52014-07-08 14:16:17 -0700486 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700487 public void phoneAccountSelected(PhoneAccountHandle accountHandle) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700488 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle);
Nancy Chen5da0fd52014-07-08 14:16:17 -0700489
490 }
491
492 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700493 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700494 *
495 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -0700496 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700497 public void conference(Call callToConferenceWith) {
498 if (callToConferenceWith != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700499 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700500 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700501 }
502
503 /**
504 * Instructs this {@code Call} to split from any conference call with which it may be
505 * connected.
506 */
507 public void splitFromConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700508 mInCallAdapter.splitFromConference(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700509 }
510
511 /**
Santos Cordona4868042014-09-04 17:39:22 -0700512 * Merges the calls within this conference. See {@link PhoneCapabilities#MERGE_CONFERENCE}.
513 */
514 public void mergeConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700515 mInCallAdapter.mergeConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700516 }
517
518 /**
519 * Swaps the calls within this conference. See {@link PhoneCapabilities#SWAP_CONFERENCE}.
520 */
521 public void swapConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700522 mInCallAdapter.swapConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700523 }
524
525 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700526 * Obtains the parent of this {@code Call} in a conference, if any.
527 *
528 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
529 * child of any conference {@code Call}s.
530 */
531 public Call getParent() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700532 if (mParentId != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700533 return mPhone.internalGetCallByTelecomId(mParentId);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700534 }
535 return null;
Ihab Awade63fadb2014-07-09 21:52:04 -0700536 }
537
538 /**
539 * Obtains the children of this conference {@code Call}, if any.
540 *
541 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
542 * {@code List} otherwise.
543 */
544 public List<Call> getChildren() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700545 if (!mChildrenCached) {
546 mChildrenCached = true;
547 mChildren.clear();
548
549 for(String id : mChildrenIds) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700550 Call call = mPhone.internalGetCallByTelecomId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700551 if (call == null) {
552 // At least one child was still not found, so do not save true for "cached"
553 mChildrenCached = false;
554 } else {
555 mChildren.add(call);
556 }
557 }
558 }
559
Ihab Awade63fadb2014-07-09 21:52:04 -0700560 return mUnmodifiableChildren;
561 }
562
563 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700564 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
565 *
566 * @return The list of conferenceable {@code Call}s.
567 */
568 public List<Call> getConferenceableCalls() {
569 return mUnmodifiableConferenceableCalls;
570 }
571
572 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700573 * Obtains the state of this {@code Call}.
574 *
575 * @return A state value, chosen from the {@code STATE_*} constants.
576 */
577 public int getState() {
578 return mState;
579 }
580
581 /**
582 * Obtains a list of canned, pre-configured message responses to present to the user as
583 * ways of rejecting this {@code Call} using via a text message.
584 *
585 * @see #reject(boolean, String)
586 *
587 * @return A list of canned text message responses.
588 */
589 public List<String> getCannedTextResponses() {
590 return mCannedTextResponses;
591 }
592
593 /**
594 * Obtains an object that can be used to display video from this {@code Call}.
595 *
Andrew Lee50aca232014-07-22 16:41:54 -0700596 * @return An {@code Call.VideoCall}.
Tyler Gunn75537ae2014-08-22 11:33:13 -0700597 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700598 */
Andrew Lee50aca232014-07-22 16:41:54 -0700599 public InCallService.VideoCall getVideoCall() {
600 return mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700601 }
602
603 /**
604 * Obtains an object containing call details.
605 *
606 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
607 * result may be {@code null}.
608 */
609 public Details getDetails() {
610 return mDetails;
611 }
612
613 /**
614 * Adds a listener to this {@code Call}.
615 *
616 * @param listener A {@code Listener}.
617 */
618 public void addListener(Listener listener) {
619 mListeners.add(listener);
620 }
621
622 /**
623 * Removes a listener from this {@code Call}.
624 *
625 * @param listener A {@code Listener}.
626 */
627 public void removeListener(Listener listener) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700628 if (listener != null) {
629 mListeners.remove(listener);
630 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700631 }
632
633 /** {@hide} */
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700634 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700635 mPhone = phone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700636 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700637 mInCallAdapter = inCallAdapter;
638 mState = STATE_NEW;
639 }
640
641 /** {@hide} */
642 final String internalGetCallId() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700643 return mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700644 }
645
646 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700647 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700648 // First, we update the internal state as far as possible before firing any updates.
Ihab Awade63fadb2014-07-09 21:52:04 -0700649 Details details = new Details(
Santos Cordon88b771d2014-07-19 13:10:40 -0700650 parcelableCall.getHandle(),
651 parcelableCall.getHandlePresentation(),
652 parcelableCall.getCallerDisplayName(),
653 parcelableCall.getCallerDisplayNamePresentation(),
654 parcelableCall.getAccountHandle(),
655 parcelableCall.getCapabilities(),
Andrew Lee223ad142014-08-27 16:33:08 -0700656 parcelableCall.getProperties(),
Santos Cordon88b771d2014-07-19 13:10:40 -0700657 parcelableCall.getDisconnectCauseCode(),
658 parcelableCall.getDisconnectCauseMsg(),
659 parcelableCall.getConnectTimeMillis(),
660 parcelableCall.getGatewayInfo(),
661 parcelableCall.getVideoState(),
Nancy Chen10798dc2014-08-08 14:00:25 -0700662 parcelableCall.getStatusHints(),
663 parcelableCall.getExtras());
Ihab Awade63fadb2014-07-09 21:52:04 -0700664 boolean detailsChanged = !Objects.equals(mDetails, details);
665 if (detailsChanged) {
666 mDetails = details;
667 }
668
669 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -0700670 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
671 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
672 mCannedTextResponses =
673 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Ihab Awade63fadb2014-07-09 21:52:04 -0700674 }
675
Andrew Lee50aca232014-07-22 16:41:54 -0700676 boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
677 if (videoCallChanged) {
678 mVideoCall = parcelableCall.getVideoCall();
Ihab Awade63fadb2014-07-09 21:52:04 -0700679 }
680
Santos Cordon88b771d2014-07-19 13:10:40 -0700681 int state = stateFromParcelableCallState(parcelableCall.getState());
Ihab Awade63fadb2014-07-09 21:52:04 -0700682 boolean stateChanged = mState != state;
683 if (stateChanged) {
684 mState = state;
685 }
686
Santos Cordon823fd3c2014-08-07 18:35:18 -0700687 String parentId = parcelableCall.getParentCallId();
688 boolean parentChanged = !Objects.equals(mParentId, parentId);
689 if (parentChanged) {
690 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700691 }
692
Santos Cordon823fd3c2014-08-07 18:35:18 -0700693 List<String> childCallIds = parcelableCall.getChildCallIds();
694 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
695 if (childrenChanged) {
696 mChildrenIds.clear();
697 mChildrenIds.addAll(parcelableCall.getChildCallIds());
698 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -0700699 }
700
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700701 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
702 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
703 for (String otherId : conferenceableCallIds) {
704 if (callIdMap.containsKey(otherId)) {
705 conferenceableCalls.add(callIdMap.get(otherId));
706 }
707 }
708
709 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
710 mConferenceableCalls.clear();
711 mConferenceableCalls.addAll(conferenceableCalls);
712 fireConferenceableCallsChanged();
713 }
714
Ihab Awade63fadb2014-07-09 21:52:04 -0700715 // Now we fire updates, ensuring that any client who listens to any of these notifications
716 // gets the most up-to-date state.
717
718 if (stateChanged) {
719 fireStateChanged(mState);
720 }
721 if (detailsChanged) {
722 fireDetailsChanged(mDetails);
723 }
724 if (cannedTextResponsesChanged) {
725 fireCannedTextResponsesLoaded(mCannedTextResponses);
726 }
Andrew Lee50aca232014-07-22 16:41:54 -0700727 if (videoCallChanged) {
728 fireVideoCallChanged(mVideoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -0700729 }
Santos Cordon823fd3c2014-08-07 18:35:18 -0700730 if (parentChanged) {
731 fireParentChanged(getParent());
732 }
733 if (childrenChanged) {
734 fireChildrenChanged(getChildren());
735 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700736
737 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
738 // remove ourselves from the Phone. Note that we do this after completing all state updates
739 // so a client can cleanly transition all their UI to the state appropriate for a
740 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
741 if (mState == STATE_DISCONNECTED) {
742 fireCallDestroyed();
743 mPhone.internalRemoveCall(this);
744 }
745 }
746
747 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -0700748 final void internalSetPostDialWait(String remaining) {
749 mRemainingPostDialSequence = remaining;
750 firePostDialWait(mRemainingPostDialSequence);
751 }
752
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700753 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -0700754 final void internalSetDisconnected() {
755 if (mState != Call.STATE_DISCONNECTED) {
756 mState = Call.STATE_DISCONNECTED;
757 fireStateChanged(mState);
758 fireCallDestroyed();
759 mPhone.internalRemoveCall(this);
760 }
761 }
762
Ihab Awade63fadb2014-07-09 21:52:04 -0700763 private void fireStateChanged(int newState) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700764 for (Listener listener : mListeners) {
765 listener.onStateChanged(this, newState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700766 }
767 }
768
769 private void fireParentChanged(Call newParent) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700770 for (Listener listener : mListeners) {
771 listener.onParentChanged(this, newParent);
Ihab Awade63fadb2014-07-09 21:52:04 -0700772 }
773 }
774
775 private void fireChildrenChanged(List<Call> children) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700776 for (Listener listener : mListeners) {
777 listener.onChildrenChanged(this, children);
Ihab Awade63fadb2014-07-09 21:52:04 -0700778 }
779 }
780
781 private void fireDetailsChanged(Details details) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700782 for (Listener listener : mListeners) {
783 listener.onDetailsChanged(this, details);
Ihab Awade63fadb2014-07-09 21:52:04 -0700784 }
785 }
786
787 private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700788 for (Listener listener : mListeners) {
789 listener.onCannedTextResponsesLoaded(this, cannedTextResponses);
Ihab Awade63fadb2014-07-09 21:52:04 -0700790 }
791 }
792
Andrew Lee50aca232014-07-22 16:41:54 -0700793 private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700794 for (Listener listener : mListeners) {
795 listener.onVideoCallChanged(this, videoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -0700796 }
797 }
798
Ihab Awade63fadb2014-07-09 21:52:04 -0700799 private void firePostDialWait(String remainingPostDialSequence) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700800 for (Listener listener : mListeners) {
801 listener.onPostDialWait(this, remainingPostDialSequence);
Ihab Awade63fadb2014-07-09 21:52:04 -0700802 }
803 }
804
805 private void fireCallDestroyed() {
Jay Shrauner229e3822014-08-15 09:23:07 -0700806 for (Listener listener : mListeners) {
807 listener.onCallDestroyed(this);
Ihab Awade63fadb2014-07-09 21:52:04 -0700808 }
809 }
810
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700811 private void fireConferenceableCallsChanged() {
Jay Shrauner229e3822014-08-15 09:23:07 -0700812 for (Listener listener : mListeners) {
813 listener.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700814 }
815 }
816
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700817 private int stateFromParcelableCallState(int parcelableCallState) {
Santos Cordon88b771d2014-07-19 13:10:40 -0700818 switch (parcelableCallState) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700819 case CallState.NEW:
Ihab Awade63fadb2014-07-09 21:52:04 -0700820 return STATE_NEW;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700821 case CallState.CONNECTING:
Nancy Chene20930f2014-08-07 16:17:21 -0700822 return STATE_CONNECTING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700823 case CallState.PRE_DIAL_WAIT:
Nancy Chen5da0fd52014-07-08 14:16:17 -0700824 return STATE_PRE_DIAL_WAIT;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700825 case CallState.DIALING:
Ihab Awade63fadb2014-07-09 21:52:04 -0700826 return STATE_DIALING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700827 case CallState.RINGING:
Ihab Awade63fadb2014-07-09 21:52:04 -0700828 return STATE_RINGING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700829 case CallState.ACTIVE:
Ihab Awade63fadb2014-07-09 21:52:04 -0700830 return STATE_ACTIVE;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700831 case CallState.ON_HOLD:
Ihab Awade63fadb2014-07-09 21:52:04 -0700832 return STATE_HOLDING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700833 case CallState.DISCONNECTED:
Ihab Awade63fadb2014-07-09 21:52:04 -0700834 return STATE_DISCONNECTED;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700835 case CallState.ABORTED:
Ihab Awade63fadb2014-07-09 21:52:04 -0700836 return STATE_DISCONNECTED;
837 default:
Santos Cordon88b771d2014-07-19 13:10:40 -0700838 Log.wtf(this, "Unrecognized CallState %s", parcelableCallState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700839 return STATE_NEW;
840 }
841 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700842}