blob: 354fa2ee6498d114e575dc8677a11606bfe486f1 [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 -070022
Andrew Lee50aca232014-07-22 16:41:54 -070023import java.lang.String;
Ihab Awade63fadb2014-07-09 21:52:04 -070024import java.util.ArrayList;
25import java.util.Collections;
26import java.util.List;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070027import java.util.Map;
Ihab Awade63fadb2014-07-09 21:52:04 -070028import java.util.Objects;
Jay Shrauner229e3822014-08-15 09:23:07 -070029import java.util.concurrent.CopyOnWriteArrayList;
Ihab Awade63fadb2014-07-09 21:52:04 -070030
31/**
32 * Represents an ongoing phone call that the in-call app should present to the user.
Ihab Awadb19a0bc2014-08-07 19:46:01 -070033 *
34 * {@hide}
Ihab Awade63fadb2014-07-09 21:52:04 -070035 */
Gabriel Pealb95f1692014-08-19 14:24:18 -070036@SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -070037public final class Call {
38 /**
39 * The state of a {@code Call} when newly created.
40 */
41 public static final int STATE_NEW = 0;
42
43 /**
44 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
45 */
46 public static final int STATE_DIALING = 1;
47
48 /**
49 * The state of an incoming {@code Call} when ringing locally, but not yet connected.
50 */
51 public static final int STATE_RINGING = 2;
52
53 /**
54 * The state of a {@code Call} when in a holding state.
55 */
56 public static final int STATE_HOLDING = 3;
57
58 /**
59 * The state of a {@code Call} when actively supporting conversation.
60 */
61 public static final int STATE_ACTIVE = 4;
62
63 /**
64 * The state of a {@code Call} when no further voice or other communication is being
65 * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
66 * is no longer active, and the local data transport has or inevitably will release resources
67 * associated with this {@code Call}.
68 */
69 public static final int STATE_DISCONNECTED = 7;
70
Nancy Chen5da0fd52014-07-08 14:16:17 -070071 /**
72 * The state of an outgoing {@code Call}, but waiting for user input before proceeding.
73 */
74 public static final int STATE_PRE_DIAL_WAIT = 8;
75
Nancy Chene20930f2014-08-07 16:17:21 -070076 /**
Nancy Chene9b7a8e2014-08-08 14:26:27 -070077 * The initial state of an outgoing {@code Call}.
78 * Common transitions are to {@link #STATE_DIALING} state for a successful call or
79 * {@link #STATE_DISCONNECTED} if it failed.
Nancy Chene20930f2014-08-07 16:17:21 -070080 */
81 public static final int STATE_CONNECTING = 9;
82
Nancy Chen513c8922014-09-17 14:47:20 -070083 /**
Tyler Gunn4afc6af2014-10-07 10:14:55 -070084 * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
85 * call has not yet been disconnected by the underlying {@code ConnectionService}. The next
86 * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
87 */
88 public static final int STATE_DISCONNECTING = 10;
89
90 /**
Nancy Chen513c8922014-09-17 14:47:20 -070091 * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
92 * extras. Used to pass the phone accounts to display on the front end to the user in order to
93 * select phone accounts to (for example) place a call.
94 *
95 * @hide
96 */
97 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
98
Ihab Awade63fadb2014-07-09 21:52:04 -070099 public static class Details {
100 private final Uri mHandle;
101 private final int mHandlePresentation;
102 private final String mCallerDisplayName;
103 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700104 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700105 private final int mCallCapabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700106 private final int mCallProperties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700107 private final DisconnectCause mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700108 private final long mConnectTimeMillis;
109 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700110 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700111 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700112 private final Bundle mExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700113
114 /**
115 * @return The handle (e.g., phone number) to which the {@code Call} is currently
116 * connected.
117 */
118 public Uri getHandle() {
119 return mHandle;
120 }
121
122 /**
123 * @return The presentation requirements for the handle. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700124 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700125 */
126 public int getHandlePresentation() {
127 return mHandlePresentation;
128 }
129
130 /**
131 * @return The display name for the caller.
132 */
133 public String getCallerDisplayName() {
134 return mCallerDisplayName;
135 }
136
137 /**
138 * @return The presentation requirements for the caller display name. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700139 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700140 */
141 public int getCallerDisplayNamePresentation() {
142 return mCallerDisplayNamePresentation;
143 }
144
145 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700146 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
147 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700148 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700149 public PhoneAccountHandle getAccountHandle() {
150 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700151 }
152
153 /**
154 * @return A bitmask of the capabilities of the {@code Call}, as defined in
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700155 * {@link PhoneCapabilities}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700156 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700157 public int getCallCapabilities() {
158 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700159 }
160
161 /**
Andrew Lee223ad142014-08-27 16:33:08 -0700162 * @return A bitmask of the properties of the {@code Call}, as defined in
163 * {@link CallProperties}.
164 */
165 public int getCallProperties() {
166 return mCallProperties;
167 }
168
169 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700170 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
Nancy Chenf4cf77c2014-09-19 10:53:21 -0700171 * by {@link android.telecom.DisconnectCause}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700172 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700173 public DisconnectCause getDisconnectCause() {
174 return mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700175 }
176
177 /**
178 * @return The time the {@code Call} has been connected. This information is updated
179 * periodically, but user interfaces should not rely on this to display any "call time
180 * clock".
181 */
182 public long getConnectTimeMillis() {
183 return mConnectTimeMillis;
184 }
185
186 /**
187 * @return Information about any calling gateway the {@code Call} may be using.
188 */
189 public GatewayInfo getGatewayInfo() {
190 return mGatewayInfo;
191 }
192
Andrew Lee7a341382014-07-15 17:05:08 -0700193 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700194 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700195 */
196 public int getVideoState() {
197 return mVideoState;
198 }
199
Ihab Awad5d0410f2014-07-30 10:07:40 -0700200 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700201 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
Ihab Awad5d0410f2014-07-30 10:07:40 -0700202 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700203 */
204 public StatusHints getStatusHints() {
205 return mStatusHints;
206 }
207
Nancy Chen10798dc2014-08-08 14:00:25 -0700208 /**
209 * @return A bundle extras to pass with the call
210 */
211 public Bundle getExtras() {
212 return mExtras;
213 }
214
Ihab Awade63fadb2014-07-09 21:52:04 -0700215 @Override
216 public boolean equals(Object o) {
217 if (o instanceof Details) {
218 Details d = (Details) o;
219 return
220 Objects.equals(mHandle, d.mHandle) &&
221 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
222 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
223 Objects.equals(mCallerDisplayNamePresentation,
224 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700225 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700226 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Andrew Lee223ad142014-08-27 16:33:08 -0700227 Objects.equals(mCallProperties, d.mCallProperties) &&
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700228 Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700229 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700230 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700231 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700232 Objects.equals(mStatusHints, d.mStatusHints) &&
233 Objects.equals(mExtras, d.mExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700234 }
235 return false;
236 }
237
238 @Override
239 public int hashCode() {
240 return
241 Objects.hashCode(mHandle) +
242 Objects.hashCode(mHandlePresentation) +
243 Objects.hashCode(mCallerDisplayName) +
244 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700245 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700246 Objects.hashCode(mCallCapabilities) +
Andrew Lee223ad142014-08-27 16:33:08 -0700247 Objects.hashCode(mCallProperties) +
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700248 Objects.hashCode(mDisconnectCause) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700249 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700250 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700251 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700252 Objects.hashCode(mStatusHints) +
253 Objects.hashCode(mExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700254 }
255
256 /** {@hide} */
257 public Details(
258 Uri handle,
259 int handlePresentation,
260 String callerDisplayName,
261 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700262 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700263 int capabilities,
Andrew Lee223ad142014-08-27 16:33:08 -0700264 int properties,
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700265 DisconnectCause disconnectCause,
Ihab Awade63fadb2014-07-09 21:52:04 -0700266 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700267 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700268 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700269 StatusHints statusHints,
270 Bundle extras) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700271 mHandle = handle;
272 mHandlePresentation = handlePresentation;
273 mCallerDisplayName = callerDisplayName;
274 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700275 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700276 mCallCapabilities = capabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700277 mCallProperties = properties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700278 mDisconnectCause = disconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700279 mConnectTimeMillis = connectTimeMillis;
280 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700281 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700282 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700283 mExtras = extras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700284 }
285 }
286
287 public static abstract class Listener {
288 /**
289 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
290 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700291 * @param call The {@code Call} invoking this method.
292 * @param state The new state of the {@code Call}.
293 */
294 public void onStateChanged(Call call, int state) {}
295
296 /**
297 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
298 *
299 * @param call The {@code Call} invoking this method.
300 * @param parent The new parent of the {@code Call}.
301 */
302 public void onParentChanged(Call call, Call parent) {}
303
304 /**
305 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
306 *
307 * @param call The {@code Call} invoking this method.
308 * @param children The new children of the {@code Call}.
309 */
310 public void onChildrenChanged(Call call, List<Call> children) {}
311
312 /**
313 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
314 *
315 * @param call The {@code Call} invoking this method.
316 * @param details A {@code Details} object describing the {@code Call}.
317 */
318 public void onDetailsChanged(Call call, Details details) {}
319
320 /**
321 * Invoked when the text messages that can be used as responses to the incoming
322 * {@code Call} are loaded from the relevant database.
323 * See {@link #getCannedTextResponses()}.
324 *
325 * @param call The {@code Call} invoking this method.
326 * @param cannedTextResponses The text messages useable as responses.
327 */
328 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
329
330 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700331 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
332 * character. This causes the post-dial signals to stop pending user confirmation. An
333 * implementation should present this choice to the user and invoke
334 * {@link #postDialContinue(boolean)} when the user makes the choice.
335 *
336 * @param call The {@code Call} invoking this method.
337 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
338 */
339 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
340
341 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700342 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700343 *
344 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700345 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Tyler Gunn75537ae2014-08-22 11:33:13 -0700346 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700347 */
Andrew Lee50aca232014-07-22 16:41:54 -0700348 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700349
350 /**
351 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
352 * up their UI for the {@code Call} in response to state transitions. Specifically,
353 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
354 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
355 * clients should wait for this method to be invoked.
356 *
357 * @param call The {@code Call} being destroyed.
358 */
359 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700360
361 /**
362 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
363 * conferenced.
364 *
365 * @param call The {@code Call} being updated.
366 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
367 * conferenced.
368 */
369 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700370 }
371
372 private final Phone mPhone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700373 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700374 private final InCallAdapter mInCallAdapter;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700375 private final List<String> mChildrenIds = new ArrayList<>();
Ihab Awade63fadb2014-07-09 21:52:04 -0700376 private final List<Call> mChildren = new ArrayList<>();
377 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Jay Shrauner229e3822014-08-15 09:23:07 -0700378 private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700379 private final List<Call> mConferenceableCalls = new ArrayList<>();
380 private final List<Call> mUnmodifiableConferenceableCalls =
381 Collections.unmodifiableList(mConferenceableCalls);
382
Santos Cordon823fd3c2014-08-07 18:35:18 -0700383 private boolean mChildrenCached;
384 private String mParentId = null;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700385 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -0700386 private List<String> mCannedTextResponses = null;
387 private String mRemainingPostDialSequence;
Andrew Lee50aca232014-07-22 16:41:54 -0700388 private InCallService.VideoCall mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700389 private Details mDetails;
Ihab Awade63fadb2014-07-09 21:52:04 -0700390
391 /**
392 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
393 *
394 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
395 * remaining or this {@code Call} is not in a post-dial state.
396 */
397 public String getRemainingPostDialSequence() {
398 return mRemainingPostDialSequence;
399 }
400
401 /**
402 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700403 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -0700404 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700405 public void answer(int videoState) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700406 mInCallAdapter.answerCall(mTelecomCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700407 }
408
409 /**
410 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
411 *
412 * @param rejectWithMessage Whether to reject with a text message.
413 * @param textMessage An optional text message with which to respond.
414 */
415 public void reject(boolean rejectWithMessage, String textMessage) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700416 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
Ihab Awade63fadb2014-07-09 21:52:04 -0700417 }
418
419 /**
420 * Instructs this {@code Call} to disconnect.
421 */
422 public void disconnect() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700423 mInCallAdapter.disconnectCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700424 }
425
426 /**
427 * Instructs this {@code Call} to go on hold.
428 */
429 public void hold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700430 mInCallAdapter.holdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700431 }
432
433 /**
434 * Instructs this {@link #STATE_HOLDING} call to release from hold.
435 */
436 public void unhold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700437 mInCallAdapter.unholdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700438 }
439
440 /**
441 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
442 *
443 * Any other currently playing DTMF tone in the specified call is immediately stopped.
444 *
445 * @param digit A character representing the DTMF digit for which to play the tone. This
446 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
447 */
448 public void playDtmfTone(char digit) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700449 mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
Ihab Awade63fadb2014-07-09 21:52:04 -0700450 }
451
452 /**
453 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
454 * currently playing.
455 *
456 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
457 * currently playing, this method will do nothing.
458 */
459 public void stopDtmfTone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700460 mInCallAdapter.stopDtmfTone(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700461 }
462
463 /**
464 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
465 *
466 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
467 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -0700468 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700469 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700470 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
471 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700472 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700473 * {@code Call} will pause playing the tones and notify listeners via
474 * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app
475 * should display to the user an indication of this state and an affordance to continue
476 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
477 * app should invoke the {@link #postDialContinue(boolean)} method.
478 *
479 * @param proceed Whether or not to continue with the post-dial sequence.
480 */
481 public void postDialContinue(boolean proceed) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700482 mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
Ihab Awade63fadb2014-07-09 21:52:04 -0700483 }
484
485 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -0700486 * Notifies this {@code Call} that an account has been selected and to proceed with placing
Nancy Chen36c62f32014-10-21 18:36:39 -0700487 * an outgoing call. Optionally sets this account as the default account.
Nancy Chen5da0fd52014-07-08 14:16:17 -0700488 */
Nancy Chen36c62f32014-10-21 18:36:39 -0700489 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
490 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
Nancy Chen5da0fd52014-07-08 14:16:17 -0700491
492 }
493
494 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700495 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700496 *
497 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -0700498 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700499 public void conference(Call callToConferenceWith) {
500 if (callToConferenceWith != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700501 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700502 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700503 }
504
505 /**
506 * Instructs this {@code Call} to split from any conference call with which it may be
507 * connected.
508 */
509 public void splitFromConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700510 mInCallAdapter.splitFromConference(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700511 }
512
513 /**
Santos Cordona4868042014-09-04 17:39:22 -0700514 * Merges the calls within this conference. See {@link PhoneCapabilities#MERGE_CONFERENCE}.
515 */
516 public void mergeConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700517 mInCallAdapter.mergeConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700518 }
519
520 /**
521 * Swaps the calls within this conference. See {@link PhoneCapabilities#SWAP_CONFERENCE}.
522 */
523 public void swapConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700524 mInCallAdapter.swapConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700525 }
526
527 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700528 * Obtains the parent of this {@code Call} in a conference, if any.
529 *
530 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
531 * child of any conference {@code Call}s.
532 */
533 public Call getParent() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700534 if (mParentId != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700535 return mPhone.internalGetCallByTelecomId(mParentId);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700536 }
537 return null;
Ihab Awade63fadb2014-07-09 21:52:04 -0700538 }
539
540 /**
541 * Obtains the children of this conference {@code Call}, if any.
542 *
543 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
544 * {@code List} otherwise.
545 */
546 public List<Call> getChildren() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700547 if (!mChildrenCached) {
548 mChildrenCached = true;
549 mChildren.clear();
550
551 for(String id : mChildrenIds) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700552 Call call = mPhone.internalGetCallByTelecomId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700553 if (call == null) {
554 // At least one child was still not found, so do not save true for "cached"
555 mChildrenCached = false;
556 } else {
557 mChildren.add(call);
558 }
559 }
560 }
561
Ihab Awade63fadb2014-07-09 21:52:04 -0700562 return mUnmodifiableChildren;
563 }
564
565 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700566 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
567 *
568 * @return The list of conferenceable {@code Call}s.
569 */
570 public List<Call> getConferenceableCalls() {
571 return mUnmodifiableConferenceableCalls;
572 }
573
574 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700575 * Obtains the state of this {@code Call}.
576 *
577 * @return A state value, chosen from the {@code STATE_*} constants.
578 */
579 public int getState() {
580 return mState;
581 }
582
583 /**
584 * Obtains a list of canned, pre-configured message responses to present to the user as
585 * ways of rejecting this {@code Call} using via a text message.
586 *
587 * @see #reject(boolean, String)
588 *
589 * @return A list of canned text message responses.
590 */
591 public List<String> getCannedTextResponses() {
592 return mCannedTextResponses;
593 }
594
595 /**
596 * Obtains an object that can be used to display video from this {@code Call}.
597 *
Andrew Lee50aca232014-07-22 16:41:54 -0700598 * @return An {@code Call.VideoCall}.
Tyler Gunn75537ae2014-08-22 11:33:13 -0700599 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700600 */
Andrew Lee50aca232014-07-22 16:41:54 -0700601 public InCallService.VideoCall getVideoCall() {
602 return mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700603 }
604
605 /**
606 * Obtains an object containing call details.
607 *
608 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
609 * result may be {@code null}.
610 */
611 public Details getDetails() {
612 return mDetails;
613 }
614
615 /**
616 * Adds a listener to this {@code Call}.
617 *
618 * @param listener A {@code Listener}.
619 */
620 public void addListener(Listener listener) {
621 mListeners.add(listener);
622 }
623
624 /**
625 * Removes a listener from this {@code Call}.
626 *
627 * @param listener A {@code Listener}.
628 */
629 public void removeListener(Listener listener) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700630 if (listener != null) {
631 mListeners.remove(listener);
632 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700633 }
634
635 /** {@hide} */
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700636 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700637 mPhone = phone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700638 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700639 mInCallAdapter = inCallAdapter;
640 mState = STATE_NEW;
641 }
642
643 /** {@hide} */
644 final String internalGetCallId() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700645 return mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700646 }
647
648 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700649 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700650 // First, we update the internal state as far as possible before firing any updates.
Ihab Awade63fadb2014-07-09 21:52:04 -0700651 Details details = new Details(
Santos Cordon88b771d2014-07-19 13:10:40 -0700652 parcelableCall.getHandle(),
653 parcelableCall.getHandlePresentation(),
654 parcelableCall.getCallerDisplayName(),
655 parcelableCall.getCallerDisplayNamePresentation(),
656 parcelableCall.getAccountHandle(),
657 parcelableCall.getCapabilities(),
Andrew Lee223ad142014-08-27 16:33:08 -0700658 parcelableCall.getProperties(),
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700659 parcelableCall.getDisconnectCause(),
Santos Cordon88b771d2014-07-19 13:10:40 -0700660 parcelableCall.getConnectTimeMillis(),
661 parcelableCall.getGatewayInfo(),
662 parcelableCall.getVideoState(),
Nancy Chen10798dc2014-08-08 14:00:25 -0700663 parcelableCall.getStatusHints(),
664 parcelableCall.getExtras());
Ihab Awade63fadb2014-07-09 21:52:04 -0700665 boolean detailsChanged = !Objects.equals(mDetails, details);
666 if (detailsChanged) {
667 mDetails = details;
668 }
669
670 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -0700671 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
672 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
673 mCannedTextResponses =
674 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Ihab Awade63fadb2014-07-09 21:52:04 -0700675 }
676
Andrew Lee50aca232014-07-22 16:41:54 -0700677 boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
678 if (videoCallChanged) {
679 mVideoCall = parcelableCall.getVideoCall();
Ihab Awade63fadb2014-07-09 21:52:04 -0700680 }
681
Santos Cordon88b771d2014-07-19 13:10:40 -0700682 int state = stateFromParcelableCallState(parcelableCall.getState());
Ihab Awade63fadb2014-07-09 21:52:04 -0700683 boolean stateChanged = mState != state;
684 if (stateChanged) {
685 mState = state;
686 }
687
Santos Cordon823fd3c2014-08-07 18:35:18 -0700688 String parentId = parcelableCall.getParentCallId();
689 boolean parentChanged = !Objects.equals(mParentId, parentId);
690 if (parentChanged) {
691 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700692 }
693
Santos Cordon823fd3c2014-08-07 18:35:18 -0700694 List<String> childCallIds = parcelableCall.getChildCallIds();
695 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
696 if (childrenChanged) {
697 mChildrenIds.clear();
698 mChildrenIds.addAll(parcelableCall.getChildCallIds());
699 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -0700700 }
701
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700702 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
703 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
704 for (String otherId : conferenceableCallIds) {
705 if (callIdMap.containsKey(otherId)) {
706 conferenceableCalls.add(callIdMap.get(otherId));
707 }
708 }
709
710 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
711 mConferenceableCalls.clear();
712 mConferenceableCalls.addAll(conferenceableCalls);
713 fireConferenceableCallsChanged();
714 }
715
Ihab Awade63fadb2014-07-09 21:52:04 -0700716 // Now we fire updates, ensuring that any client who listens to any of these notifications
717 // gets the most up-to-date state.
718
719 if (stateChanged) {
720 fireStateChanged(mState);
721 }
722 if (detailsChanged) {
723 fireDetailsChanged(mDetails);
724 }
725 if (cannedTextResponsesChanged) {
726 fireCannedTextResponsesLoaded(mCannedTextResponses);
727 }
Andrew Lee50aca232014-07-22 16:41:54 -0700728 if (videoCallChanged) {
729 fireVideoCallChanged(mVideoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -0700730 }
Santos Cordon823fd3c2014-08-07 18:35:18 -0700731 if (parentChanged) {
732 fireParentChanged(getParent());
733 }
734 if (childrenChanged) {
735 fireChildrenChanged(getChildren());
736 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700737
738 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
739 // remove ourselves from the Phone. Note that we do this after completing all state updates
740 // so a client can cleanly transition all their UI to the state appropriate for a
741 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
742 if (mState == STATE_DISCONNECTED) {
743 fireCallDestroyed();
744 mPhone.internalRemoveCall(this);
745 }
746 }
747
748 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -0700749 final void internalSetPostDialWait(String remaining) {
750 mRemainingPostDialSequence = remaining;
751 firePostDialWait(mRemainingPostDialSequence);
752 }
753
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700754 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -0700755 final void internalSetDisconnected() {
756 if (mState != Call.STATE_DISCONNECTED) {
757 mState = Call.STATE_DISCONNECTED;
758 fireStateChanged(mState);
759 fireCallDestroyed();
760 mPhone.internalRemoveCall(this);
761 }
762 }
763
Ihab Awade63fadb2014-07-09 21:52:04 -0700764 private void fireStateChanged(int newState) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700765 for (Listener listener : mListeners) {
766 listener.onStateChanged(this, newState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700767 }
768 }
769
770 private void fireParentChanged(Call newParent) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700771 for (Listener listener : mListeners) {
772 listener.onParentChanged(this, newParent);
Ihab Awade63fadb2014-07-09 21:52:04 -0700773 }
774 }
775
776 private void fireChildrenChanged(List<Call> children) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700777 for (Listener listener : mListeners) {
778 listener.onChildrenChanged(this, children);
Ihab Awade63fadb2014-07-09 21:52:04 -0700779 }
780 }
781
782 private void fireDetailsChanged(Details details) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700783 for (Listener listener : mListeners) {
784 listener.onDetailsChanged(this, details);
Ihab Awade63fadb2014-07-09 21:52:04 -0700785 }
786 }
787
788 private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700789 for (Listener listener : mListeners) {
790 listener.onCannedTextResponsesLoaded(this, cannedTextResponses);
Ihab Awade63fadb2014-07-09 21:52:04 -0700791 }
792 }
793
Andrew Lee50aca232014-07-22 16:41:54 -0700794 private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700795 for (Listener listener : mListeners) {
796 listener.onVideoCallChanged(this, videoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -0700797 }
798 }
799
Ihab Awade63fadb2014-07-09 21:52:04 -0700800 private void firePostDialWait(String remainingPostDialSequence) {
Jay Shrauner229e3822014-08-15 09:23:07 -0700801 for (Listener listener : mListeners) {
802 listener.onPostDialWait(this, remainingPostDialSequence);
Ihab Awade63fadb2014-07-09 21:52:04 -0700803 }
804 }
805
806 private void fireCallDestroyed() {
Jay Shrauner229e3822014-08-15 09:23:07 -0700807 for (Listener listener : mListeners) {
808 listener.onCallDestroyed(this);
Ihab Awade63fadb2014-07-09 21:52:04 -0700809 }
810 }
811
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700812 private void fireConferenceableCallsChanged() {
Jay Shrauner229e3822014-08-15 09:23:07 -0700813 for (Listener listener : mListeners) {
814 listener.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700815 }
816 }
817
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700818 private int stateFromParcelableCallState(int parcelableCallState) {
Santos Cordon88b771d2014-07-19 13:10:40 -0700819 switch (parcelableCallState) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700820 case CallState.NEW:
Ihab Awade63fadb2014-07-09 21:52:04 -0700821 return STATE_NEW;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700822 case CallState.CONNECTING:
Nancy Chene20930f2014-08-07 16:17:21 -0700823 return STATE_CONNECTING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700824 case CallState.PRE_DIAL_WAIT:
Nancy Chen5da0fd52014-07-08 14:16:17 -0700825 return STATE_PRE_DIAL_WAIT;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700826 case CallState.DIALING:
Ihab Awade63fadb2014-07-09 21:52:04 -0700827 return STATE_DIALING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700828 case CallState.RINGING:
Ihab Awade63fadb2014-07-09 21:52:04 -0700829 return STATE_RINGING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700830 case CallState.ACTIVE:
Ihab Awade63fadb2014-07-09 21:52:04 -0700831 return STATE_ACTIVE;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700832 case CallState.ON_HOLD:
Ihab Awade63fadb2014-07-09 21:52:04 -0700833 return STATE_HOLDING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700834 case CallState.DISCONNECTED:
Ihab Awade63fadb2014-07-09 21:52:04 -0700835 return STATE_DISCONNECTED;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700836 case CallState.ABORTED:
Ihab Awade63fadb2014-07-09 21:52:04 -0700837 return STATE_DISCONNECTED;
Tyler Gunn4afc6af2014-10-07 10:14:55 -0700838 case CallState.DISCONNECTING:
839 return STATE_DISCONNECTING;
Ihab Awade63fadb2014-07-09 21:52:04 -0700840 default:
Santos Cordon88b771d2014-07-19 13:10:40 -0700841 Log.wtf(this, "Unrecognized CallState %s", parcelableCallState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700842 return STATE_NEW;
843 }
844 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700845}