blob: f988ac8a759b72711e781b3bf92404f3d725cb18 [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
17package android.telecomm;
18
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -070019import android.app.PendingIntent;
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;
30
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 */
36public final class Call {
37 /**
38 * The state of a {@code Call} when newly created.
39 */
40 public static final int STATE_NEW = 0;
41
42 /**
43 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
44 */
45 public static final int STATE_DIALING = 1;
46
47 /**
48 * The state of an incoming {@code Call} when ringing locally, but not yet connected.
49 */
50 public static final int STATE_RINGING = 2;
51
52 /**
53 * The state of a {@code Call} when in a holding state.
54 */
55 public static final int STATE_HOLDING = 3;
56
57 /**
58 * The state of a {@code Call} when actively supporting conversation.
59 */
60 public static final int STATE_ACTIVE = 4;
61
62 /**
63 * The state of a {@code Call} when no further voice or other communication is being
64 * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
65 * is no longer active, and the local data transport has or inevitably will release resources
66 * associated with this {@code Call}.
67 */
68 public static final int STATE_DISCONNECTED = 7;
69
Nancy Chen5da0fd52014-07-08 14:16:17 -070070 /**
71 * The state of an outgoing {@code Call}, but waiting for user input before proceeding.
72 */
73 public static final int STATE_PRE_DIAL_WAIT = 8;
74
Nancy Chene20930f2014-08-07 16:17:21 -070075 /**
Nancy Chene9b7a8e2014-08-08 14:26:27 -070076 * The initial state of an outgoing {@code Call}.
77 * Common transitions are to {@link #STATE_DIALING} state for a successful call or
78 * {@link #STATE_DISCONNECTED} if it failed.
Nancy Chene20930f2014-08-07 16:17:21 -070079 */
80 public static final int STATE_CONNECTING = 9;
81
Ihab Awade63fadb2014-07-09 21:52:04 -070082 public static class Details {
83 private final Uri mHandle;
84 private final int mHandlePresentation;
85 private final String mCallerDisplayName;
86 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -070087 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -070088 private final int mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -070089 private final int mDisconnectCauseCode;
Ihab Awadb19a0bc2014-08-07 19:46:01 -070090 private final String mDisconnectCauseMessage;
Ihab Awade63fadb2014-07-09 21:52:04 -070091 private final long mConnectTimeMillis;
92 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -070093 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -070094 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -070095 private final Bundle mExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -070096
97 /**
98 * @return The handle (e.g., phone number) to which the {@code Call} is currently
99 * connected.
100 */
101 public Uri getHandle() {
102 return mHandle;
103 }
104
105 /**
106 * @return The presentation requirements for the handle. See
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700107 * {@link PropertyPresentation} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700108 */
109 public int getHandlePresentation() {
110 return mHandlePresentation;
111 }
112
113 /**
114 * @return The display name for the caller.
115 */
116 public String getCallerDisplayName() {
117 return mCallerDisplayName;
118 }
119
120 /**
121 * @return The presentation requirements for the caller display name. See
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700122 * {@link PropertyPresentation} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700123 */
124 public int getCallerDisplayNamePresentation() {
125 return mCallerDisplayNamePresentation;
126 }
127
128 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700129 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
130 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700131 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700132 public PhoneAccountHandle getAccountHandle() {
133 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700134 }
135
136 /**
137 * @return A bitmask of the capabilities of the {@code Call}, as defined in
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700138 * {@link PhoneCapabilities}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700139 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700140 public int getCallCapabilities() {
141 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700142 }
143
144 /**
145 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
146 * as a code chosen from among those declared in {@link DisconnectCause}.
147 */
148 public int getDisconnectCauseCode() {
149 return mDisconnectCauseCode;
150 }
151
152 /**
153 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, an optional reason for
154 * disconnection expressed as a free text message.
155 */
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700156 public String getDisconnectCauseMessage() {
157 return mDisconnectCauseMessage;
Ihab Awade63fadb2014-07-09 21:52:04 -0700158 }
159
160 /**
161 * @return The time the {@code Call} has been connected. This information is updated
162 * periodically, but user interfaces should not rely on this to display any "call time
163 * clock".
164 */
165 public long getConnectTimeMillis() {
166 return mConnectTimeMillis;
167 }
168
169 /**
170 * @return Information about any calling gateway the {@code Call} may be using.
171 */
172 public GatewayInfo getGatewayInfo() {
173 return mGatewayInfo;
174 }
175
Andrew Lee7a341382014-07-15 17:05:08 -0700176 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700177 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700178 */
179 public int getVideoState() {
180 return mVideoState;
181 }
182
Ihab Awad5d0410f2014-07-30 10:07:40 -0700183 /**
184 * @return The current {@link android.telecomm.StatusHints}, or {@code null} if none
185 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700186 */
187 public StatusHints getStatusHints() {
188 return mStatusHints;
189 }
190
Nancy Chen10798dc2014-08-08 14:00:25 -0700191 /**
192 * @return A bundle extras to pass with the call
193 */
194 public Bundle getExtras() {
195 return mExtras;
196 }
197
Ihab Awade63fadb2014-07-09 21:52:04 -0700198 @Override
199 public boolean equals(Object o) {
200 if (o instanceof Details) {
201 Details d = (Details) o;
202 return
203 Objects.equals(mHandle, d.mHandle) &&
204 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
205 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
206 Objects.equals(mCallerDisplayNamePresentation,
207 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700208 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700209 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700210 Objects.equals(mDisconnectCauseCode, d.mDisconnectCauseCode) &&
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700211 Objects.equals(mDisconnectCauseMessage, d.mDisconnectCauseMessage) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700212 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700213 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700214 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700215 Objects.equals(mStatusHints, d.mStatusHints) &&
216 Objects.equals(mExtras, d.mExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700217 }
218 return false;
219 }
220
221 @Override
222 public int hashCode() {
223 return
224 Objects.hashCode(mHandle) +
225 Objects.hashCode(mHandlePresentation) +
226 Objects.hashCode(mCallerDisplayName) +
227 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700228 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700229 Objects.hashCode(mCallCapabilities) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700230 Objects.hashCode(mDisconnectCauseCode) +
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700231 Objects.hashCode(mDisconnectCauseMessage) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700232 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700233 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700234 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700235 Objects.hashCode(mStatusHints) +
236 Objects.hashCode(mExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700237 }
238
239 /** {@hide} */
240 public Details(
241 Uri handle,
242 int handlePresentation,
243 String callerDisplayName,
244 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700245 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700246 int capabilities,
247 int disconnectCauseCode,
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700248 String disconnectCauseMessage,
Ihab Awade63fadb2014-07-09 21:52:04 -0700249 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700250 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700251 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700252 StatusHints statusHints,
253 Bundle extras) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700254 mHandle = handle;
255 mHandlePresentation = handlePresentation;
256 mCallerDisplayName = callerDisplayName;
257 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700258 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700259 mCallCapabilities = capabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700260 mDisconnectCauseCode = disconnectCauseCode;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700261 mDisconnectCauseMessage = disconnectCauseMessage;
Ihab Awade63fadb2014-07-09 21:52:04 -0700262 mConnectTimeMillis = connectTimeMillis;
263 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700264 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700265 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700266 mExtras = extras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700267 }
268 }
269
270 public static abstract class Listener {
271 /**
272 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
273 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700274 * @param call The {@code Call} invoking this method.
275 * @param state The new state of the {@code Call}.
276 */
277 public void onStateChanged(Call call, int state) {}
278
279 /**
280 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
281 *
282 * @param call The {@code Call} invoking this method.
283 * @param parent The new parent of the {@code Call}.
284 */
285 public void onParentChanged(Call call, Call parent) {}
286
287 /**
288 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
289 *
290 * @param call The {@code Call} invoking this method.
291 * @param children The new children of the {@code Call}.
292 */
293 public void onChildrenChanged(Call call, List<Call> children) {}
294
295 /**
296 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
297 *
298 * @param call The {@code Call} invoking this method.
299 * @param details A {@code Details} object describing the {@code Call}.
300 */
301 public void onDetailsChanged(Call call, Details details) {}
302
303 /**
304 * Invoked when the text messages that can be used as responses to the incoming
305 * {@code Call} are loaded from the relevant database.
306 * See {@link #getCannedTextResponses()}.
307 *
308 * @param call The {@code Call} invoking this method.
309 * @param cannedTextResponses The text messages useable as responses.
310 */
311 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
312
313 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700314 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
315 * character. This causes the post-dial signals to stop pending user confirmation. An
316 * implementation should present this choice to the user and invoke
317 * {@link #postDialContinue(boolean)} when the user makes the choice.
318 *
319 * @param call The {@code Call} invoking this method.
320 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
321 */
322 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
323
324 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700325 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700326 *
327 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700328 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700329 */
Andrew Lee50aca232014-07-22 16:41:54 -0700330 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700331
332 /**
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700333 * Launches an activity for this connection on top of the in-call UI.
334 *
335 * @param call The {@code Call} invoking this method.
336 * @param intent The intent to use to start the activity.
337 */
338 public void onStartActivity(Call call, PendingIntent intent) {}
339
340 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700341 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
342 * up their UI for the {@code Call} in response to state transitions. Specifically,
343 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
344 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
345 * clients should wait for this method to be invoked.
346 *
347 * @param call The {@code Call} being destroyed.
348 */
349 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700350
351 /**
352 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
353 * conferenced.
354 *
355 * @param call The {@code Call} being updated.
356 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
357 * conferenced.
358 */
359 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700360 }
361
362 private final Phone mPhone;
363 private final String mTelecommCallId;
364 private final InCallAdapter mInCallAdapter;
Ihab Awade63fadb2014-07-09 21:52:04 -0700365 private final List<Call> mChildren = new ArrayList<>();
366 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700367 private final List<Listener> mListeners = new ArrayList<>();
368 private final List<Call> mConferenceableCalls = new ArrayList<>();
369 private final List<Call> mUnmodifiableConferenceableCalls =
370 Collections.unmodifiableList(mConferenceableCalls);
371
372 private Call mParent = null;
373 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -0700374 private List<String> mCannedTextResponses = null;
375 private String mRemainingPostDialSequence;
Andrew Lee50aca232014-07-22 16:41:54 -0700376 private InCallService.VideoCall mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700377 private Details mDetails;
Ihab Awade63fadb2014-07-09 21:52:04 -0700378
379 /**
380 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
381 *
382 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
383 * remaining or this {@code Call} is not in a post-dial state.
384 */
385 public String getRemainingPostDialSequence() {
386 return mRemainingPostDialSequence;
387 }
388
389 /**
390 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700391 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -0700392 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700393 public void answer(int videoState) {
394 mInCallAdapter.answerCall(mTelecommCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700395 }
396
397 /**
398 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
399 *
400 * @param rejectWithMessage Whether to reject with a text message.
401 * @param textMessage An optional text message with which to respond.
402 */
403 public void reject(boolean rejectWithMessage, String textMessage) {
404 mInCallAdapter.rejectCall(mTelecommCallId, rejectWithMessage, textMessage);
405 }
406
407 /**
408 * Instructs this {@code Call} to disconnect.
409 */
410 public void disconnect() {
411 mInCallAdapter.disconnectCall(mTelecommCallId);
412 }
413
414 /**
415 * Instructs this {@code Call} to go on hold.
416 */
417 public void hold() {
418 mInCallAdapter.holdCall(mTelecommCallId);
419 }
420
421 /**
422 * Instructs this {@link #STATE_HOLDING} call to release from hold.
423 */
424 public void unhold() {
425 mInCallAdapter.unholdCall(mTelecommCallId);
426 }
427
428 /**
429 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
430 *
431 * Any other currently playing DTMF tone in the specified call is immediately stopped.
432 *
433 * @param digit A character representing the DTMF digit for which to play the tone. This
434 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
435 */
436 public void playDtmfTone(char digit) {
437 mInCallAdapter.playDtmfTone(mTelecommCallId, digit);
438 }
439
440 /**
441 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
442 * currently playing.
443 *
444 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
445 * currently playing, this method will do nothing.
446 */
447 public void stopDtmfTone() {
448 mInCallAdapter.stopDtmfTone(mTelecommCallId);
449 }
450
451 /**
452 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
453 *
454 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
455 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -0700456 *
Evan Charlton10197192014-07-19 15:00:29 -0700457 * If the DTMF string contains a {@link TelecommManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700458 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
459 *
Evan Charlton10197192014-07-19 15:00:29 -0700460 * If the DTMF string contains a {@link TelecommManager#DTMF_CHARACTER_WAIT} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700461 * {@code Call} will pause playing the tones and notify listeners via
462 * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app
463 * should display to the user an indication of this state and an affordance to continue
464 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
465 * app should invoke the {@link #postDialContinue(boolean)} method.
466 *
467 * @param proceed Whether or not to continue with the post-dial sequence.
468 */
469 public void postDialContinue(boolean proceed) {
470 mInCallAdapter.postDialContinue(mTelecommCallId, proceed);
471 }
472
473 /**
474 * Notifies this {@code Call} that the phone account user interface element was touched.
Ihab Awade63fadb2014-07-09 21:52:04 -0700475 */
476 public void phoneAccountClicked() {
477 mInCallAdapter.phoneAccountClicked(mTelecommCallId);
478 }
479
480 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -0700481 * Notifies this {@code Call} that an account has been selected and to proceed with placing
482 * an outgoing call.
Nancy Chen5da0fd52014-07-08 14:16:17 -0700483 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700484 public void phoneAccountSelected(PhoneAccountHandle accountHandle) {
485 mInCallAdapter.phoneAccountSelected(mTelecommCallId, accountHandle);
Nancy Chen5da0fd52014-07-08 14:16:17 -0700486
487 }
488
489 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700490 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700491 *
492 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -0700493 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700494 public void conference(Call callToConferenceWith) {
495 if (callToConferenceWith != null) {
496 mInCallAdapter.conference(mTelecommCallId, callToConferenceWith.mTelecommCallId);
497 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700498 }
499
500 /**
501 * Instructs this {@code Call} to split from any conference call with which it may be
502 * connected.
503 */
504 public void splitFromConference() {
505 mInCallAdapter.splitFromConference(mTelecommCallId);
506 }
507
508 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700509 * Obtains the parent of this {@code Call} in a conference, if any.
510 *
511 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
512 * child of any conference {@code Call}s.
513 */
514 public Call getParent() {
515 return mParent;
516 }
517
518 /**
519 * Obtains the children of this conference {@code Call}, if any.
520 *
521 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
522 * {@code List} otherwise.
523 */
524 public List<Call> getChildren() {
525 return mUnmodifiableChildren;
526 }
527
528 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700529 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
530 *
531 * @return The list of conferenceable {@code Call}s.
532 */
533 public List<Call> getConferenceableCalls() {
534 return mUnmodifiableConferenceableCalls;
535 }
536
537 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700538 * Obtains the state of this {@code Call}.
539 *
540 * @return A state value, chosen from the {@code STATE_*} constants.
541 */
542 public int getState() {
543 return mState;
544 }
545
546 /**
547 * Obtains a list of canned, pre-configured message responses to present to the user as
548 * ways of rejecting this {@code Call} using via a text message.
549 *
550 * @see #reject(boolean, String)
551 *
552 * @return A list of canned text message responses.
553 */
554 public List<String> getCannedTextResponses() {
555 return mCannedTextResponses;
556 }
557
558 /**
559 * Obtains an object that can be used to display video from this {@code Call}.
560 *
Andrew Lee50aca232014-07-22 16:41:54 -0700561 * @return An {@code Call.VideoCall}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700562 */
Andrew Lee50aca232014-07-22 16:41:54 -0700563 public InCallService.VideoCall getVideoCall() {
564 return mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700565 }
566
567 /**
568 * Obtains an object containing call details.
569 *
570 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
571 * result may be {@code null}.
572 */
573 public Details getDetails() {
574 return mDetails;
575 }
576
577 /**
578 * Adds a listener to this {@code Call}.
579 *
580 * @param listener A {@code Listener}.
581 */
582 public void addListener(Listener listener) {
583 mListeners.add(listener);
584 }
585
586 /**
587 * Removes a listener from this {@code Call}.
588 *
589 * @param listener A {@code Listener}.
590 */
591 public void removeListener(Listener listener) {
592 mListeners.remove(listener);
593 }
594
595 /** {@hide} */
596 Call(Phone phone, String telecommCallId, InCallAdapter inCallAdapter) {
597 mPhone = phone;
598 mTelecommCallId = telecommCallId;
599 mInCallAdapter = inCallAdapter;
600 mState = STATE_NEW;
601 }
602
603 /** {@hide} */
604 final String internalGetCallId() {
605 return mTelecommCallId;
606 }
607
608 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700609 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700610 // First, we update the internal state as far as possible before firing any updates.
Ihab Awade63fadb2014-07-09 21:52:04 -0700611 Details details = new Details(
Santos Cordon88b771d2014-07-19 13:10:40 -0700612 parcelableCall.getHandle(),
613 parcelableCall.getHandlePresentation(),
614 parcelableCall.getCallerDisplayName(),
615 parcelableCall.getCallerDisplayNamePresentation(),
616 parcelableCall.getAccountHandle(),
617 parcelableCall.getCapabilities(),
618 parcelableCall.getDisconnectCauseCode(),
619 parcelableCall.getDisconnectCauseMsg(),
620 parcelableCall.getConnectTimeMillis(),
621 parcelableCall.getGatewayInfo(),
622 parcelableCall.getVideoState(),
Nancy Chen10798dc2014-08-08 14:00:25 -0700623 parcelableCall.getStatusHints(),
624 parcelableCall.getExtras());
Ihab Awade63fadb2014-07-09 21:52:04 -0700625 boolean detailsChanged = !Objects.equals(mDetails, details);
626 if (detailsChanged) {
627 mDetails = details;
628 }
629
630 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -0700631 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
632 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
633 mCannedTextResponses =
634 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Ihab Awade63fadb2014-07-09 21:52:04 -0700635 }
636
Andrew Lee50aca232014-07-22 16:41:54 -0700637 boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
638 if (videoCallChanged) {
639 mVideoCall = parcelableCall.getVideoCall();
Ihab Awade63fadb2014-07-09 21:52:04 -0700640 }
641
Santos Cordon88b771d2014-07-19 13:10:40 -0700642 int state = stateFromParcelableCallState(parcelableCall.getState());
Ihab Awade63fadb2014-07-09 21:52:04 -0700643 boolean stateChanged = mState != state;
644 if (stateChanged) {
645 mState = state;
646 }
647
Santos Cordon88b771d2014-07-19 13:10:40 -0700648 if (parcelableCall.getParentCallId() != null) {
649 mParent = mPhone.internalGetCallByTelecommId(parcelableCall.getParentCallId());
Ihab Awade63fadb2014-07-09 21:52:04 -0700650 }
651
652 mChildren.clear();
Santos Cordon88b771d2014-07-19 13:10:40 -0700653 if (parcelableCall.getChildCallIds() != null) {
654 for (int i = 0; i < parcelableCall.getChildCallIds().size(); i++) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700655 mChildren.add(mPhone.internalGetCallByTelecommId(
Santos Cordon88b771d2014-07-19 13:10:40 -0700656 parcelableCall.getChildCallIds().get(i)));
Ihab Awade63fadb2014-07-09 21:52:04 -0700657 }
658 }
659
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700660 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
661 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
662 for (String otherId : conferenceableCallIds) {
663 if (callIdMap.containsKey(otherId)) {
664 conferenceableCalls.add(callIdMap.get(otherId));
665 }
666 }
667
668 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
669 mConferenceableCalls.clear();
670 mConferenceableCalls.addAll(conferenceableCalls);
671 fireConferenceableCallsChanged();
672 }
673
Ihab Awade63fadb2014-07-09 21:52:04 -0700674 // Now we fire updates, ensuring that any client who listens to any of these notifications
675 // gets the most up-to-date state.
676
677 if (stateChanged) {
678 fireStateChanged(mState);
679 }
680 if (detailsChanged) {
681 fireDetailsChanged(mDetails);
682 }
683 if (cannedTextResponsesChanged) {
684 fireCannedTextResponsesLoaded(mCannedTextResponses);
685 }
Andrew Lee50aca232014-07-22 16:41:54 -0700686 if (videoCallChanged) {
687 fireVideoCallChanged(mVideoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -0700688 }
689
690 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
691 // remove ourselves from the Phone. Note that we do this after completing all state updates
692 // so a client can cleanly transition all their UI to the state appropriate for a
693 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
694 if (mState == STATE_DISCONNECTED) {
695 fireCallDestroyed();
696 mPhone.internalRemoveCall(this);
697 }
698 }
699
700 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -0700701 final void internalSetPostDialWait(String remaining) {
702 mRemainingPostDialSequence = remaining;
703 firePostDialWait(mRemainingPostDialSequence);
704 }
705
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700706 /** {@hide} */
707 final void internalStartActivity(PendingIntent intent) {
708 fireStartActivity(intent);
709 }
710
Ihab Awade63fadb2014-07-09 21:52:04 -0700711 private void fireStateChanged(int newState) {
712 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
713 for (int i = 0; i < listeners.length; i++) {
714 listeners[i].onStateChanged(this, newState);
715 }
716 }
717
718 private void fireParentChanged(Call newParent) {
719 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
720 for (int i = 0; i < listeners.length; i++) {
721 listeners[i].onParentChanged(this, newParent);
722 }
723 }
724
725 private void fireChildrenChanged(List<Call> children) {
726 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
727 for (int i = 0; i < listeners.length; i++) {
728 listeners[i].onChildrenChanged(this, children);
729 }
730 }
731
732 private void fireDetailsChanged(Details details) {
733 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
734 for (int i = 0; i < listeners.length; i++) {
735 listeners[i].onDetailsChanged(this, details);
736 }
737 }
738
739 private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
740 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
741 for (int i = 0; i < listeners.length; i++) {
742 listeners[i].onCannedTextResponsesLoaded(this, cannedTextResponses);
743 }
744 }
745
Andrew Lee50aca232014-07-22 16:41:54 -0700746 private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700747 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
748 for (int i = 0; i < listeners.length; i++) {
Andrew Lee50aca232014-07-22 16:41:54 -0700749 listeners[i].onVideoCallChanged(this, videoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -0700750 }
751 }
752
Ihab Awade63fadb2014-07-09 21:52:04 -0700753 private void firePostDialWait(String remainingPostDialSequence) {
754 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
755 for (int i = 0; i < listeners.length; i++) {
756 listeners[i].onPostDialWait(this, remainingPostDialSequence);
757 }
758 }
759
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700760 private void fireStartActivity(PendingIntent intent) {
761 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
762 for (int i = 0; i < listeners.length; i++) {
763 listeners[i].onStartActivity(this, intent);
764 }
765 }
766
Ihab Awade63fadb2014-07-09 21:52:04 -0700767 private void fireCallDestroyed() {
768 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
769 for (int i = 0; i < listeners.length; i++) {
770 listeners[i].onCallDestroyed(this);
771 }
772 }
773
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700774 private void fireConferenceableCallsChanged() {
775 Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
776 for (int i = 0; i < listeners.length; i++) {
777 listeners[i].onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
778 }
779 }
780
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700781 private int stateFromParcelableCallState(int parcelableCallState) {
Santos Cordon88b771d2014-07-19 13:10:40 -0700782 switch (parcelableCallState) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700783 case CallState.NEW:
Ihab Awade63fadb2014-07-09 21:52:04 -0700784 return STATE_NEW;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700785 case CallState.CONNECTING:
Nancy Chene20930f2014-08-07 16:17:21 -0700786 return STATE_CONNECTING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700787 case CallState.PRE_DIAL_WAIT:
Nancy Chen5da0fd52014-07-08 14:16:17 -0700788 return STATE_PRE_DIAL_WAIT;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700789 case CallState.DIALING:
Ihab Awade63fadb2014-07-09 21:52:04 -0700790 return STATE_DIALING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700791 case CallState.RINGING:
Ihab Awade63fadb2014-07-09 21:52:04 -0700792 return STATE_RINGING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700793 case CallState.ACTIVE:
Ihab Awade63fadb2014-07-09 21:52:04 -0700794 return STATE_ACTIVE;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700795 case CallState.ON_HOLD:
Ihab Awade63fadb2014-07-09 21:52:04 -0700796 return STATE_HOLDING;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700797 case CallState.DISCONNECTED:
Ihab Awade63fadb2014-07-09 21:52:04 -0700798 return STATE_DISCONNECTED;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700799 case CallState.ABORTED:
Ihab Awade63fadb2014-07-09 21:52:04 -0700800 return STATE_DISCONNECTED;
801 default:
Santos Cordon88b771d2014-07-19 13:10:40 -0700802 Log.wtf(this, "Unrecognized CallState %s", parcelableCallState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700803 return STATE_NEW;
804 }
805 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700806}