Call.java revision e19cc005ddbff5313d6f7288587630b2410d005c
10407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad/*
20407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * Copyright (C) 2014 The Android Open Source Project
30407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad *
40407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * Licensed under the Apache License, Version 2.0 (the "License");
50407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * you may not use this file except in compliance with the License.
60407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * You may obtain a copy of the License at
70407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad *
80407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad *      http://www.apache.org/licenses/LICENSE-2.0
90407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad *
100407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * Unless required by applicable law or agreed to in writing, software
110407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * distributed under the License is distributed on an "AS IS" BASIS,
120407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * See the License for the specific language governing permissions and
140407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * limitations under the License.
150407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad */
160407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad
179f2bed31374a56487f370be01224baf6ce97e8adBen Giladpackage com.android.telecomm;
189f2bed31374a56487f370be01224baf6ce97e8adBen Gilad
1999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.content.ContentUris;
2099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.graphics.Bitmap;
2199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.graphics.drawable.Drawable;
22ce704b9a5d9cf7db30a8c865975c70e5cbc0dc5cSailesh Nepalimport android.net.Uri;
2384fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepalimport android.os.Bundle;
24fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport android.os.Handler;
2599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.provider.ContactsContract.Contacts;
260b03b4b143234302f098ea18de3c32658b455ecaSantos Cordonimport android.telecomm.CallInfo;
2784fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepalimport android.telecomm.CallServiceDescriptor;
280b03b4b143234302f098ea18de3c32658b455ecaSantos Cordonimport android.telecomm.CallState;
2933501635c2cd21f40793041eff3b8ce3a5710d49Yorke Leeimport android.telecomm.GatewayInfo;
30ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport android.telecomm.Response;
3177d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chenimport android.telecomm.Subscription;
32766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordonimport android.telecomm.TelecommConstants;
3379ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordonimport android.telephony.DisconnectCause;
346aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalimport android.telephony.PhoneNumberUtils;
35fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport android.text.TextUtils;
360b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon
37a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chenimport com.android.internal.telecomm.ICallVideoProvider;
38fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport com.android.internal.telephony.CallerInfo;
39fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport com.android.internal.telephony.CallerInfoAsyncQuery;
40fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport com.android.internal.telephony.CallerInfoAsyncQuery.OnQueryCompleteListener;
41ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport com.android.internal.telephony.SmsApplication;
4299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport com.android.telecomm.ContactsAsyncHelper.OnImageLoadCompleteListener;
4361d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordonimport com.google.common.base.Preconditions;
44ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport com.google.common.collect.Sets;
4561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
46ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport java.util.Collections;
47a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordonimport java.util.LinkedList;
48a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordonimport java.util.List;
499199078322aea6df26f0d304a28a9a6d040f0717Sailesh Nepalimport java.util.Locale;
506192561b1f56d7c4e6c650e178e07ba61ad02667Ben Giladimport java.util.Set;
510407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad
522495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad/**
532495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad *  Encapsulates all aspects of a given phone call throughout its lifecycle, starting
542495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad *  from the time the call intent was received by Telecomm (vs. the time the call was
552495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad *  connected etc).
562495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad */
575a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepalfinal class Call implements OutgoingCallResponse {
58766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
59766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    /**
60766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     * Listener for events on the call.
61766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     */
62766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    interface Listener {
63766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        void onSuccessfulOutgoingCall(Call call);
645a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        void onFailedOutgoingCall(Call call, int errorCode, String errorMsg);
655a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        void onCancelledOutgoingCall(Call call);
66766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        void onSuccessfulIncomingCall(Call call, CallInfo callInfo);
67766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        void onFailedIncomingCall(Call call);
68cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad        void onRequestingRingback(Call call, boolean requestingRingback);
69352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton        void onPostDialWait(Call call, String remaining);
70a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        void onIsConferenceCapableChanged(Call call, boolean isConferenceCapable);
71a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        void onExpiredConferenceCall(Call call);
72a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        void onConfirmedConferenceCall(Call call);
73a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        void onParentChanged(Call call);
74a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        void onChildrenChanged(Call call);
75ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        void onCannedSmsResponsesLoaded(Call call);
76a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen        void onCallVideoProviderChanged(Call call);
77e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn        void onFeaturesChanged(Call call);
78766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
79766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
80fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    private static final OnQueryCompleteListener sCallerInfoQueryListener =
8199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            new OnQueryCompleteListener() {
8299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                /** ${inheritDoc} */
8399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                @Override
8499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                public void onQueryComplete(int token, Object cookie, CallerInfo callerInfo) {
8599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                    if (cookie != null) {
8699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        ((Call) cookie).setCallerInfo(callerInfo, token);
8799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                    }
88fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon                }
8999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            };
9099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon
9199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    private static final OnImageLoadCompleteListener sPhotoLoadListener =
9299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            new OnImageLoadCompleteListener() {
9399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                /** ${inheritDoc} */
9499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                @Override
9599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                public void onImageLoadComplete(
9699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        int token, Drawable photo, Bitmap photoIcon, Object cookie) {
9799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                    if (cookie != null) {
9899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        ((Call) cookie).setPhoto(photo, photoIcon, token);
9999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                    }
10099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                }
10199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            };
1020407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad
103810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal    /** True if this is an incoming call. */
104810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal    private final boolean mIsIncoming;
105810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal
1060407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad    /**
1070407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     * The time this call was created, typically also the time this call was added to the set
1080407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     * of pending outgoing calls (mPendingOutgoingCalls) that's maintained by the switchboard.
1090407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     * Beyond logging and such, may also be used for bookkeeping and specifically for marking
1100407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     * certain call attempts as failed attempts.
1110407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     */
1128c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    private final long mCreationTimeMillis = System.currentTimeMillis();
1138c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal
114fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    /** The gateway information associated with this call. This stores the original call handle
115fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     * that the user is attempting to connect to via the gateway, the actual handle to dial in
116fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     * order to connect the call via the gateway, as well as the package name of the gateway
117fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     * service. */
118fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    private final GatewayInfo mGatewayInfo;
119fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon
12077d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen    private final Subscription mSubscription;
12177d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen
1222174fb56907fddf5680355e097f4425f837983e2Santos Cordon    private final Handler mHandler = new Handler();
1232174fb56907fddf5680355e097f4425f837983e2Santos Cordon
1248c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    private long mConnectTimeMillis;
1250407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad
12661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    /** The state of the call. */
12761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    private CallState mState;
12861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
12961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    /** The handle with which to establish this call. */
130ce704b9a5d9cf7db30a8c865975c70e5cbc0dc5cSailesh Nepal    private Uri mHandle;
13161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
1320407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad    /**
1338e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad     * The call service which is attempted or already connecting this call.
134681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon     */
135c195e3613af47a49e76821d3f24c05adb71cf920Santos Cordon    private CallServiceWrapper mCallService;
136681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon
1378e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad    /**
1386192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * The set of call services that were attempted in the process of placing/switching this call
1396192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * but turned out unsuitable.  Only used in the context of call switching.
1406192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     */
1416192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    private Set<CallServiceWrapper> mIncompatibleCallServices;
1426192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad
1436aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    private boolean mIsEmergencyCall;
1446aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
145b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati    private boolean mSpeakerphoneOn;
146b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati
1476192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    /**
14879ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     * Disconnect cause for the call. Only valid if the state of the call is DISCONNECTED.
14979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     * See {@link android.telephony.DisconnectCause}.
15079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     */
1518c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    private int mDisconnectCause = DisconnectCause.NOT_VALID;
15279ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon
15379ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    /**
15479ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     * Additional disconnect information provided by the call service.
15579ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     */
15679ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    private String mDisconnectMessage;
15779ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon
15884fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    /** Info used by the call services. */
1598c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    private Bundle mExtras = Bundle.EMPTY;
16084fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
16184fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    /** The Uri to dial to perform the handoff. If this is null then handoff is not supported. */
16284fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    private Uri mHandoffHandle;
16384fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
16484fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    /**
16584fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal     * References the call that is being handed off. This value is non-null for untracked calls
16684fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal     * that are being used to perform a handoff.
16784fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal     */
16884fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    private Call mOriginalCall;
16984fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
17079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    /**
1718c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal     * The descriptor for the call service that this call is being switched to, null if handoff is
1728c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal     * not in progress.
1738c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal     */
1748c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    private CallServiceDescriptor mHandoffCallServiceDescriptor;
1758c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal
176766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    /** Set of listeners on this call. */
177766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    private Set<Listener> mListeners = Sets.newHashSet();
178766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
179682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon    private OutgoingCallProcessor mOutgoingCallProcessor;
180682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon
181682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon    // TODO(santoscordon): The repositories should be changed into singleton types.
182682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon    private CallServiceRepository mCallServiceRepository;
183682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon
184fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    /** Caller information retrieved from the latest contact query. */
185fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    private CallerInfo mCallerInfo;
186fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon
187fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    /** The latest token used with a contact info query. */
188fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    private int mQueryToken = 0;
189fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon
190cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad    /** Whether this call is requesting that Telecomm play the ringback tone on its behalf. */
191cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad    private boolean mRequestingRingback = false;
192cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad
1932174fb56907fddf5680355e097f4425f837983e2Santos Cordon    /** Incoming call-info to use when direct-to-voicemail query finishes. */
1942174fb56907fddf5680355e097f4425f837983e2Santos Cordon    private CallInfo mPendingDirectToVoicemailCallInfo;
1952174fb56907fddf5680355e097f4425f837983e2Santos Cordon
196a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    private boolean mIsConferenceCapable = false;
197a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
198a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    private boolean mIsConference = false;
199a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
200a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    private Call mParentCall = null;
201a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
202a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    private List<Call> mChildCalls = new LinkedList<>();
203a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
204ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    /** Set of text message responses allowed for this call, if applicable. */
205ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    private List<String> mCannedSmsResponses = Collections.EMPTY_LIST;
206ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
207ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    /** Whether an attempt has been made to load the text message responses. */
208ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    private boolean mCannedSmsResponsesLoadingStarted = false;
209ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
210a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen    private ICallVideoProvider mCallVideoProvider;
211a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen
212e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    /** Features associated with the call which the InCall UI may wish to show icons for. */
213e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    private int mFeatures;
214e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn
2158c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    /**
216e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal     * Creates an empty call object.
217810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal     *
218810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal     * @param isIncoming True if this is an incoming call.
219493e8f2ac0c611b43265c72715b71f6ec59bba0eSantos Cordon     */
220a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    Call(boolean isIncoming, boolean isConference) {
22177d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen        this(null, null, null, isIncoming, isConference);
222493e8f2ac0c611b43265c72715b71f6ec59bba0eSantos Cordon    }
223493e8f2ac0c611b43265c72715b71f6ec59bba0eSantos Cordon
224493e8f2ac0c611b43265c72715b71f6ec59bba0eSantos Cordon    /**
2250407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     * Persists the specified parameters and initializes the new instance.
2260407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     *
2270407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     * @param handle The handle to dial.
22833501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee     * @param gatewayInfo Gateway information to use for the call.
22977d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen     * @param subscription Subscription information to use for the call.
230810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal     * @param isIncoming True if this is an incoming call.
2310407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     */
23277d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen    Call(Uri handle, GatewayInfo gatewayInfo, Subscription subscription,
23377d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen            boolean isIncoming, boolean isConference) {
234a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        mState = isConference ? CallState.ACTIVE : CallState.NEW;
2356aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        setHandle(handle);
23633501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee        mGatewayInfo = gatewayInfo;
23777d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen        mSubscription = subscription;
238810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal        mIsIncoming = isIncoming;
239a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        mIsConference = isConference;
240ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        maybeLoadCannedSmsResponses();
2410407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad    }
2420407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad
243766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    void addListener(Listener listener) {
244766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        mListeners.add(listener);
245766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
246766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
247766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    void removeListener(Listener listener) {
248766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        mListeners.remove(listener);
249766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
250766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
25161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    /** {@inheritDoc} */
25261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    @Override public String toString() {
2534538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal        String component = null;
2544538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal        if (mCallService != null && mCallService.getComponentName() != null) {
2554538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal            component = mCallService.getComponentName().flattenToShortString();
2564538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal        }
2574538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal        return String.format(Locale.US, "[%s, %s, %s]", mState, component, Log.piiHandle(mHandle));
25861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    }
25961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
2600b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon    CallState getState() {
261a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (mIsConference) {
262a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            if (!mChildCalls.isEmpty()) {
263a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon                // If we have child calls, just return the child call.
264a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon                return mChildCalls.get(0).getState();
265a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            }
266a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            return CallState.ACTIVE;
267a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        } else {
268a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            return mState;
269a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
2700b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon    }
2710b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon
2720b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon    /**
2730b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon     * Sets the call state. Although there exists the notion of appropriate state transitions
2740b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon     * (see {@link CallState}), in practice those expectations break down when cellular systems
2750b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon     * misbehave and they do this very often. The result is that we do not enforce state transitions
2760b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon     * and instead keep the code resilient to unexpected state changes.
2770b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon     */
278810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal    void setState(CallState newState) {
27979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon        Preconditions.checkState(newState != CallState.DISCONNECTED ||
28079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon                mDisconnectCause != DisconnectCause.NOT_VALID);
281810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal        if (mState != newState) {
282810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal            Log.v(this, "setState %s -> %s", mState, newState);
283810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal            mState = newState;
284ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            maybeLoadCannedSmsResponses();
285810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal        }
2860b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon    }
2870b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon
288cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad    void setRequestingRingback(boolean requestingRingback) {
289cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad        mRequestingRingback = requestingRingback;
290cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad        for (Listener l : mListeners) {
291cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad            l.onRequestingRingback(this, mRequestingRingback);
292cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad        }
293cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad    }
294cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad
295cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad    boolean isRequestingRingback() {
296cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad        return mRequestingRingback;
297cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad    }
298cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad
299ce704b9a5d9cf7db30a8c865975c70e5cbc0dc5cSailesh Nepal    Uri getHandle() {
3000bf5b912285e328a8f5eeec158d6caf17845b9f8Ben Gilad        return mHandle;
3010bf5b912285e328a8f5eeec158d6caf17845b9f8Ben Gilad    }
3020bf5b912285e328a8f5eeec158d6caf17845b9f8Ben Gilad
303ce704b9a5d9cf7db30a8c865975c70e5cbc0dc5cSailesh Nepal    void setHandle(Uri handle) {
304fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        if ((mHandle == null && handle != null) || (mHandle != null && !mHandle.equals(handle))) {
305fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon            mHandle = handle;
306fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon            mIsEmergencyCall = mHandle != null && PhoneNumberUtils.isLocalEmergencyNumber(
3076625545769bd9c5aa15b7e1ee9402f75ad799e81Yorke Lee                    TelecommApp.getInstance(), mHandle.getSchemeSpecificPart());
308fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon            startCallerInfoLookup();
309fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        }
3106aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    }
3116aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
31299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    String getName() {
31399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon        return mCallerInfo == null ? null : mCallerInfo.name;
31499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    }
31599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon
31699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    Bitmap getPhotoIcon() {
31799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon        return mCallerInfo == null ? null : mCallerInfo.cachedPhotoIcon;
31899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    }
31999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon
32099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    Drawable getPhoto() {
32199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon        return mCallerInfo == null ? null : mCallerInfo.cachedPhoto;
32299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    }
32399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon
32479ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    /**
32579ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     * @param disconnectCause The reason for the disconnection, any of
32679ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     *         {@link android.telephony.DisconnectCause}.
32779ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     * @param disconnectMessage Optional call-service-provided message about the disconnect.
32879ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon     */
32979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    void setDisconnectCause(int disconnectCause, String disconnectMessage) {
33079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon        // TODO: Consider combining this method with a setDisconnected() method that is totally
33179ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon        // separate from setState.
33279ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon        mDisconnectCause = disconnectCause;
33379ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon        mDisconnectMessage = disconnectMessage;
33479ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    }
33579ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon
33679ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    int getDisconnectCause() {
33779ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon        return mDisconnectCause;
33879ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    }
33979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon
34079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    String getDisconnectMessage() {
34179ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon        return mDisconnectMessage;
34279ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon    }
34379ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon
3446aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    boolean isEmergencyCall() {
3456aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        return mIsEmergencyCall;
34661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    }
34761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
34833501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee    /**
34933501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee     * @return The original handle this call is associated with. In-call services should use this
35033501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee     * handle when indicating in their UI the handle that is being called.
35133501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee     */
35233501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee    public Uri getOriginalHandle() {
35333501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee        if (mGatewayInfo != null && !mGatewayInfo.isEmpty()) {
35433501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee            return mGatewayInfo.getOriginalHandle();
35533501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee        }
35633501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee        return getHandle();
35733501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee    }
35833501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee
35933501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee    GatewayInfo getGatewayInfo() {
36033501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee        return mGatewayInfo;
36133501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee    }
36233501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee
36377d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen    Subscription getSubscription() {
36477d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen        return mSubscription;
36577d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen    }
36677d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen
367810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal    boolean isIncoming() {
368810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal        return mIsIncoming;
369810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal    }
370810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal
3710407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad    /**
3720407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     * @return The "age" of this call object in milliseconds, which typically also represents the
3738c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal     *     period since this call was added to the set pending outgoing calls, see
3748c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal     *     mCreationTimeMillis.
3750407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad     */
3768c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    long getAgeMillis() {
3778c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal        return System.currentTimeMillis() - mCreationTimeMillis;
3780407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad    }
3790b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon
380f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee    /**
381f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee     * @return The time when this call object was created and added to the set of pending outgoing
382f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee     *     calls.
383f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee     */
3848c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    long getCreationTimeMillis() {
3858c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal        return mCreationTimeMillis;
3868c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    }
3878c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal
3888c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    long getConnectTimeMillis() {
3898c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal        return mConnectTimeMillis;
3908c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    }
3918c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal
3928c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    void setConnectTimeMillis(long connectTimeMillis) {
3938c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal        mConnectTimeMillis = connectTimeMillis;
394f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee    }
395f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee
396a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    boolean isConferenceCapable() {
397a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        return mIsConferenceCapable;
398a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
399a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
400a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    void setIsConferenceCapable(boolean isConferenceCapable) {
401a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (mIsConferenceCapable != isConferenceCapable) {
402a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            mIsConferenceCapable = isConferenceCapable;
403a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            for (Listener l : mListeners) {
404a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon                l.onIsConferenceCapableChanged(this, mIsConferenceCapable);
405a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            }
406a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
407a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
408a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
409a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    Call getParentCall() {
410a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        return mParentCall;
411a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
412a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
413a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    List<Call> getChildCalls() {
414a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        return mChildCalls;
415a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
416a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
417c195e3613af47a49e76821d3f24c05adb71cf920Santos Cordon    CallServiceWrapper getCallService() {
418681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon        return mCallService;
419681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon    }
420681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon
421c195e3613af47a49e76821d3f24c05adb71cf920Santos Cordon    void setCallService(CallServiceWrapper callService) {
4220e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal        setCallService(callService, null);
4230e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal    }
4240e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal
4250e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal    /**
4260e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal     * Changes the call service this call is associated with. If callToReplace is non-null then this
4270e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal     * call takes its place within the call service.
4280e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal     */
4290e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal    void setCallService(CallServiceWrapper callService, Call callToReplace) {
4308e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad        Preconditions.checkNotNull(callService);
4318e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad
432adee12dd6b3e85ce3ae419329226c9aa72c184fcYorke Lee        clearCallService();
4338e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad
4348e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad        callService.incrementAssociatedCallCount();
435681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon        mCallService = callService;
4360e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal        if (callToReplace == null) {
4370e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal            mCallService.addCall(this);
4380e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal        } else {
4390e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal            mCallService.replaceCall(this, callToReplace);
4400e5410a58043ce059884fdc8811a280655e5a920Sailesh Nepal        }
441681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon    }
442681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon
443681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon    /**
444681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon     * Clears the associated call service.
445681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon     */
446681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon    void clearCallService() {
447adee12dd6b3e85ce3ae419329226c9aa72c184fcYorke Lee        if (mCallService != null) {
448c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            CallServiceWrapper callServiceTemp = mCallService;
449adee12dd6b3e85ce3ae419329226c9aa72c184fcYorke Lee            mCallService = null;
450c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            callServiceTemp.removeCall(this);
451c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon
452c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            // Decrementing the count can cause the service to unbind, which itself can trigger the
453c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            // service-death code.  Since the service death code tries to clean up any associated
454c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            // calls, we need to make sure to remove that information (e.g., removeCall()) before
455c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            // we decrement. Technically, invoking removeCall() prior to decrementing is all that is
456c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            // necessary, but cleaning up mCallService prior to triggering an unbind is good to do.
457c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            // If you change this, make sure to update {@link clearCallServiceSelector} as well.
458c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon            decrementAssociatedCallCount(callServiceTemp);
459adee12dd6b3e85ce3ae419329226c9aa72c184fcYorke Lee        }
4608e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad    }
4618e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad
4628e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad    /**
463766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     * Starts the incoming call flow through the switchboard. When switchboard completes, it will
464766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     * invoke handle[Un]SuccessfulIncomingCall.
465766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     *
466766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     * @param descriptor The relevant call-service descriptor.
467766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     * @param extras The optional extras passed via
468766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     *         {@link TelecommConstants#EXTRA_INCOMING_CALL_EXTRAS}.
469766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     */
470766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    void startIncoming(CallServiceDescriptor descriptor, Bundle extras) {
471766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        Switchboard.getInstance().retrieveIncomingCall(this, descriptor, extras);
472766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
473766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
4742174fb56907fddf5680355e097f4425f837983e2Santos Cordon    /**
4752174fb56907fddf5680355e097f4425f837983e2Santos Cordon     * Takes a verified incoming call and uses the handle to lookup direct-to-voicemail property
4762174fb56907fddf5680355e097f4425f837983e2Santos Cordon     * from the contacts provider. The call is not yet exposed to the user at this point and
4772174fb56907fddf5680355e097f4425f837983e2Santos Cordon     * the result of the query will determine if the call is rejected or passed through to the
4782174fb56907fddf5680355e097f4425f837983e2Santos Cordon     * in-call UI.
4792174fb56907fddf5680355e097f4425f837983e2Santos Cordon     */
4802174fb56907fddf5680355e097f4425f837983e2Santos Cordon    void handleVerifiedIncoming(CallInfo callInfo) {
481766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        Preconditions.checkState(callInfo.getState() == CallState.RINGING);
4822174fb56907fddf5680355e097f4425f837983e2Santos Cordon
4832174fb56907fddf5680355e097f4425f837983e2Santos Cordon        // We do not handle incoming calls immediately when they are verified by the call service.
4842174fb56907fddf5680355e097f4425f837983e2Santos Cordon        // We allow the caller-info-query code to execute first so that we can read the
4852174fb56907fddf5680355e097f4425f837983e2Santos Cordon        // direct-to-voicemail property before deciding if we want to show the incoming call to the
4862174fb56907fddf5680355e097f4425f837983e2Santos Cordon        // user or if we want to reject the call.
4872174fb56907fddf5680355e097f4425f837983e2Santos Cordon        mPendingDirectToVoicemailCallInfo = callInfo;
4882174fb56907fddf5680355e097f4425f837983e2Santos Cordon
4892174fb56907fddf5680355e097f4425f837983e2Santos Cordon        // Setting the handle triggers the caller info lookup code.
490766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        setHandle(callInfo.getHandle());
491766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
4922174fb56907fddf5680355e097f4425f837983e2Santos Cordon        // Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
4932174fb56907fddf5680355e097f4425f837983e2Santos Cordon        // showing the user the incoming call screen.
4942174fb56907fddf5680355e097f4425f837983e2Santos Cordon        mHandler.postDelayed(new Runnable() {
4952174fb56907fddf5680355e097f4425f837983e2Santos Cordon            @Override
4962174fb56907fddf5680355e097f4425f837983e2Santos Cordon            public void run() {
4972174fb56907fddf5680355e097f4425f837983e2Santos Cordon                processDirectToVoicemail();
4982174fb56907fddf5680355e097f4425f837983e2Santos Cordon            }
499a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }, Timeouts.getDirectToVoicemailMillis());
5002174fb56907fddf5680355e097f4425f837983e2Santos Cordon    }
5012174fb56907fddf5680355e097f4425f837983e2Santos Cordon
5022174fb56907fddf5680355e097f4425f837983e2Santos Cordon    void processDirectToVoicemail() {
5032174fb56907fddf5680355e097f4425f837983e2Santos Cordon        if (mPendingDirectToVoicemailCallInfo != null) {
5042174fb56907fddf5680355e097f4425f837983e2Santos Cordon            if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
5052174fb56907fddf5680355e097f4425f837983e2Santos Cordon                Log.i(this, "Directing call to voicemail: %s.", this);
5062174fb56907fddf5680355e097f4425f837983e2Santos Cordon                // TODO(santoscordon): Once we move State handling from CallsManager to Call, we
5072174fb56907fddf5680355e097f4425f837983e2Santos Cordon                // will not need to set RINGING state prior to calling reject.
5082174fb56907fddf5680355e097f4425f837983e2Santos Cordon                setState(CallState.RINGING);
509ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                reject(false, null);
5102174fb56907fddf5680355e097f4425f837983e2Santos Cordon            } else {
5112174fb56907fddf5680355e097f4425f837983e2Santos Cordon                // TODO(santoscordon): Make this class (not CallsManager) responsible for changing
5122174fb56907fddf5680355e097f4425f837983e2Santos Cordon                // the call state to RINGING.
5132174fb56907fddf5680355e097f4425f837983e2Santos Cordon
5142174fb56907fddf5680355e097f4425f837983e2Santos Cordon                // TODO(santoscordon): Replace this with state transition to RINGING.
5152174fb56907fddf5680355e097f4425f837983e2Santos Cordon                for (Listener l : mListeners) {
5162174fb56907fddf5680355e097f4425f837983e2Santos Cordon                    l.onSuccessfulIncomingCall(this, mPendingDirectToVoicemailCallInfo);
5172174fb56907fddf5680355e097f4425f837983e2Santos Cordon                }
5182174fb56907fddf5680355e097f4425f837983e2Santos Cordon            }
519766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
5202174fb56907fddf5680355e097f4425f837983e2Santos Cordon            mPendingDirectToVoicemailCallInfo = null;
521766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        }
522766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
523766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
524766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    void handleFailedIncoming() {
525766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        clearCallService();
526766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
527766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        // TODO: Needs more specific disconnect error for this case.
528766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED, null);
529766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        setState(CallState.DISCONNECTED);
530766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
531766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        // TODO(santoscordon): Replace this with state transitions related to "connecting".
532766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        for (Listener l : mListeners) {
533766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon            l.onFailedIncomingCall(this);
534766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        }
535766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
536766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
537766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    /**
538682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon     * Starts the outgoing call sequence.  Upon completion, there should exist an active connection
539682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon     * through a call service (or the call will have failed).
540766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon     */
541766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    void startOutgoing() {
542682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon        Preconditions.checkState(mOutgoingCallProcessor == null);
543682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon
544682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon        mOutgoingCallProcessor = new OutgoingCallProcessor(
5455a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal                this, Switchboard.getInstance().getCallServiceRepository(), this);
546682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon        mOutgoingCallProcessor.process();
547766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
548766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
5495a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal    @Override
5505a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal    public void onOutgoingCallSuccess() {
551766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        // TODO(santoscordon): Replace this with state transitions related to "connecting".
552766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        for (Listener l : mListeners) {
553766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon            l.onSuccessfulOutgoingCall(this);
554766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        }
5555a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        mOutgoingCallProcessor = null;
5565a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal    }
5575a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal
5585a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal    @Override
5595a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal    public void onOutgoingCallFailure(int code, String msg) {
5605a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        // TODO(santoscordon): Replace this with state transitions related to "connecting".
5615a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        for (Listener l : mListeners) {
5625a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal            l.onFailedOutgoingCall(this, code, msg);
5635a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        }
5645a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal
5655a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        clearCallService();
5665a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        mOutgoingCallProcessor = null;
567766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
568766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
5695a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal    @Override
5705a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal    public void onOutgoingCallCancel() {
571766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        // TODO(santoscordon): Replace this with state transitions related to "connecting".
572766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        for (Listener l : mListeners) {
5735a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal            l.onCancelledOutgoingCall(this);
574766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        }
575682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon
576682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon        clearCallService();
5775a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal        mOutgoingCallProcessor = null;
578766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    }
579766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
580766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon    /**
5816192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * Adds the specified call service to the list of incompatible services.  The set is used when
5826192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * attempting to switch a phone call between call services such that incompatible services can
5836192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * be avoided.
5846192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     *
5856192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * @param callService The incompatible call service.
5866192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     */
5876192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    void addIncompatibleCallService(CallServiceWrapper callService) {
5886192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad        if (mIncompatibleCallServices == null) {
5896192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad            mIncompatibleCallServices = Sets.newHashSet();
5906192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad        }
5916192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad        mIncompatibleCallServices.add(callService);
5926192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    }
5936192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad
5946192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    /**
5956192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * Checks whether or not the specified callService was identified as incompatible in the
5966192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * context of this call.
5976192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     *
5986192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * @param callService The call service to evaluate.
5996192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     * @return True upon incompatible call services and false otherwise.
6006192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad     */
6016192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    boolean isIncompatibleCallService(CallServiceWrapper callService) {
6026192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad        return mIncompatibleCallServices != null &&
6036192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad                mIncompatibleCallServices.contains(callService);
6046192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    }
6056192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad
6066192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad    /**
60774549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad     * Plays the specified DTMF tone.
60874549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad     */
60974549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad    void playDtmfTone(char digit) {
61074549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad        if (mCallService == null) {
61174549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad            Log.w(this, "playDtmfTone() request on a call without a call service.");
61274549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad        } else {
613e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            Log.i(this, "Send playDtmfTone to call service for call %s", this);
614e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            mCallService.playDtmfTone(this, digit);
61574549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad        }
61674549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad    }
61774549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad
61874549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad    /**
61974549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad     * Stops playing any currently playing DTMF tone.
62074549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad     */
62174549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad    void stopDtmfTone() {
62274549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad        if (mCallService == null) {
62374549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad            Log.w(this, "stopDtmfTone() request on a call without a call service.");
62474549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad        } else {
625e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            Log.i(this, "Send stopDtmfTone to call service for call %s", this);
626e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            mCallService.stopDtmfTone(this);
62774549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad        }
62874549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad    }
62974549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad
63074549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad    /**
631049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon     * Attempts to disconnect the call through the call service.
632049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon     */
633049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon    void disconnect() {
634766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon        if (mState == CallState.NEW) {
635682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon            Log.v(this, "Aborting call %s", this);
636682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon            abort();
63774d420be72fa30735fe9b7a25715f6db046c0398Santos Cordon        } else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) {
638766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon            Preconditions.checkNotNull(mCallService);
639766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon
640e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            Log.i(this, "Send disconnect to call service for call: %s", this);
641c195e3613af47a49e76821d3f24c05adb71cf920Santos Cordon            // The call isn't officially disconnected until the call service confirms that the call
642c195e3613af47a49e76821d3f24c05adb71cf920Santos Cordon            // was actually disconnected. Only then is the association between call and call service
643c195e3613af47a49e76821d3f24c05adb71cf920Santos Cordon            // severed, see {@link CallsManager#markCallAsDisconnected}.
644e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            mCallService.disconnect(this);
645049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon        }
646049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon    }
647049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon
648682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon    void abort() {
649682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon        if (mOutgoingCallProcessor != null) {
650682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon            mOutgoingCallProcessor.abort();
651682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon        }
652682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon    }
653682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon
6540b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon    /**
65561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon     * Answers the call if it is ringing.
65661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon     */
65761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    void answer() {
65861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        Preconditions.checkNotNull(mCallService);
65961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
66061d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        // Check to verify that the call is still in the ringing state. A call can change states
66161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        // between the time the user hits 'answer' and Telecomm receives the command.
66261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        if (isRinging("answer")) {
66361d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon            // At this point, we are asking the call service to answer but we don't assume that
66461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon            // it will work. Instead, we wait until confirmation from the call service that the
66561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon            // call is in a non-RINGING state before changing the UI. See
66661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon            // {@link CallServiceAdapter#setActive} and other set* methods.
667e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            mCallService.answer(this);
66861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        }
66961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    }
67061d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
67161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    /**
67261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon     * Rejects the call if it is ringing.
673ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *
674ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * @param rejectWithMessage Whether to send a text message as part of the call rejection.
675ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * @param textMessage An optional text message to send as part of the rejection.
67661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon     */
677ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    void reject(boolean rejectWithMessage, String textMessage) {
67861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        Preconditions.checkNotNull(mCallService);
67961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
68061d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        // Check to verify that the call is still in the ringing state. A call can change states
68161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        // between the time the user hits 'reject' and Telecomm receives the command.
68261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        if (isRinging("reject")) {
683e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            mCallService.reject(this);
68461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        }
68561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    }
68661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
68761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    /**
688cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee     * Puts the call on hold if it is currently active.
689cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee     */
690cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee    void hold() {
691cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee        Preconditions.checkNotNull(mCallService);
692cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee
693cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee        if (mState == CallState.ACTIVE) {
694e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            mCallService.hold(this);
695cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee        }
696cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee    }
697cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee
698cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee    /**
699cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee     * Releases the call from hold if it is currently active.
700cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee     */
701cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee    void unhold() {
702cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee        Preconditions.checkNotNull(mCallService);
703cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee
704cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee        if (mState == CallState.ON_HOLD) {
705e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal            mCallService.unhold(this);
706cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee        }
707cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee    }
708cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee
709cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee    /**
7100b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon     * @return An object containing read-only information about this call.
7110b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon     */
712e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal    CallInfo toCallInfo(String callId) {
71384fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        CallServiceDescriptor descriptor = null;
71484fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        if (mCallService != null) {
71584fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal            descriptor = mCallService.getDescriptor();
71684fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        } else if (mOriginalCall != null && mOriginalCall.mCallService != null) {
71784fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal            descriptor = mOriginalCall.mCallService.getDescriptor();
71884fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        }
719571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon        Bundle extras = mExtras;
720571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon        if (mGatewayInfo != null && mGatewayInfo.getGatewayProviderPackageName() != null &&
721571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon                mGatewayInfo.getOriginalHandle() != null) {
722571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon            extras = (Bundle) mExtras.clone();
723571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon            extras.putString(
724571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon                    NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
725571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon                    mGatewayInfo.getGatewayProviderPackageName());
726571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon            extras.putParcelable(
727571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon                    NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
728571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon                    mGatewayInfo.getOriginalHandle());
729571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon
730571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon        }
73177d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen        return new CallInfo(callId, mState, mHandle, mGatewayInfo, mSubscription,
73277d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen                extras, descriptor);
7330b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon    }
7340b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon
7356aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    /** Checks if this is a live call or not. */
7366aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    boolean isAlive() {
7376aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        switch (mState) {
7386aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            case NEW:
7396aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            case RINGING:
7406aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            case DISCONNECTED:
7416aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            case ABORTED:
7426aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal                return false;
7436aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            default:
7446aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal                return true;
7456aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        }
7466aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    }
7476aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
74840f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon    boolean isActive() {
74940f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon        switch (mState) {
75040f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon            case ACTIVE:
75140f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon            case POST_DIAL:
75240f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon            case POST_DIAL_WAIT:
75340f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                return true;
75440f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon            default:
75540f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                return false;
75640f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon        }
75740f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon    }
75840f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon
75984fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    Bundle getExtras() {
76084fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        return mExtras;
76184fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    }
76284fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
76384fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    void setExtras(Bundle extras) {
76484fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        mExtras = extras;
76584fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    }
76684fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
76784fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    Uri getHandoffHandle() {
76884fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        return mHandoffHandle;
76984fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    }
77084fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
77184fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    void setHandoffHandle(Uri handoffHandle) {
77284fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        mHandoffHandle = handoffHandle;
77384fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    }
77484fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
77584fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    Call getOriginalCall() {
77684fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        return mOriginalCall;
77784fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    }
77884fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
77984fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    void setOriginalCall(Call originalCall) {
78084fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal        mOriginalCall = originalCall;
78184fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal    }
78284fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal
7838c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    CallServiceDescriptor getHandoffCallServiceDescriptor() {
7848c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal        return mHandoffCallServiceDescriptor;
7858c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    }
7868c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal
7878c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    void setHandoffCallServiceDescriptor(CallServiceDescriptor descriptor) {
7888c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal        mHandoffCallServiceDescriptor = descriptor;
7898c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    }
7908c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal
7915ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon    Uri getRingtone() {
7925ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon        return mCallerInfo == null ? null : mCallerInfo.contactRingtoneUri;
7935ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon    }
7945ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon
795352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton    void onPostDialWait(String remaining) {
796352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton        for (Listener l : mListeners) {
797352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton            l.onPostDialWait(this, remaining);
798352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton        }
799352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton    }
800352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton
801352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton    void postDialContinue(boolean proceed) {
802352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton        getCallService().onPostDialContinue(this, proceed);
803352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton    }
804352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton
805a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    void conferenceInto(Call conferenceCall) {
806a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (mCallService == null) {
807a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            Log.w(this, "conference requested on a call without a call service.");
808a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        } else {
809a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            mCallService.conference(conferenceCall, this);
810a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
811a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
812a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
813a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    void expireConference() {
814a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        // The conference call expired before we got a confirmation of the conference from the
815a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        // call service...so start shutting down.
816a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        clearCallService();
817a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        for (Listener l : mListeners) {
818a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            l.onExpiredConferenceCall(this);
819a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
820a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
821a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
822a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    void confirmConference() {
823a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        Log.v(this, "confirming Conf call %s", mListeners);
824a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        for (Listener l : mListeners) {
825a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            l.onConfirmedConferenceCall(this);
826a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
827a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
828a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
829a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    void splitFromConference() {
830a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        // TODO(santoscordon): todo
831a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
832a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
833a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    void setParentCall(Call parentCall) {
834a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (parentCall == this) {
835a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            Log.e(this, new Exception(), "setting the parent to self");
836a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            return;
837a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
838a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        Preconditions.checkState(parentCall == null || mParentCall == null);
839a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
840a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        Call oldParent = mParentCall;
841a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (mParentCall != null) {
842a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            mParentCall.removeChildCall(this);
843a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
844a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        mParentCall = parentCall;
845a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (mParentCall != null) {
846a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            mParentCall.addChildCall(this);
847a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
848a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
849a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        for (Listener l : mListeners) {
850a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            l.onParentChanged(this);
851a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
852a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
853a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
854a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    private void addChildCall(Call call) {
855a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (!mChildCalls.contains(call)) {
856a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            mChildCalls.add(call);
857a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
858a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            for (Listener l : mListeners) {
859a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon                l.onChildrenChanged(this);
860a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            }
861a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
862a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
863a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
864a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    private void removeChildCall(Call call) {
865a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        if (mChildCalls.remove(call)) {
866a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            for (Listener l : mListeners) {
867a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon                l.onChildrenChanged(this);
868a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon            }
869a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon        }
870a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon    }
871a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon
8720b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon    /**
873ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * Return whether the user can respond to this {@code Call} via an SMS message.
874ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *
875ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * @return true if the "Respond via SMS" feature should be enabled
876ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * for this incoming call.
877ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *
878ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * The general rule is that we *do* allow "Respond via SMS" except for
879ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * the few (relatively rare) cases where we know for sure it won't
880ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * work, namely:
881ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *   - a bogus or blank incoming number
882ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *   - a call from a SIP address
883ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *   - a "call presentation" that doesn't allow the number to be revealed
884ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *
885ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * In all other cases, we allow the user to respond via SMS.
886ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     *
887ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * Note that this behavior isn't perfect; for example we have no way
888ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * to detect whether the incoming call is from a landline (with most
889ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * networks at least), so we still enable this feature even though
890ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     * SMSes to that number will silently fail.
891ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad     */
892ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    boolean isRespondViaSmsCapable() {
893ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        if (mState != CallState.RINGING) {
894ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            return false;
895ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        }
896ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
897ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        if (getHandle() == null) {
898ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            // No incoming number known or call presentation is "PRESENTATION_RESTRICTED", in
899ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            // other words, the user should not be able to see the incoming phone number.
900ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            return false;
901ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        }
902ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
903ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        if (PhoneNumberUtils.isUriNumber(getHandle().toString())) {
904ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            // The incoming number is actually a URI (i.e. a SIP address),
905ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            // not a regular PSTN phone number, and we can't send SMSes to
906ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            // SIP addresses.
907ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            // (TODO: That might still be possible eventually, though. Is
908ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            // there some SIP-specific equivalent to sending a text message?)
909ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            return false;
910ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        }
911ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
912ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        // Is there a valid SMS application on the phone?
913ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        if (SmsApplication.getDefaultRespondViaMessageApplication(TelecommApp.getInstance(),
914ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                true /*updateIfNeeded*/) == null) {
915ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            return false;
916ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        }
917ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
918ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        // TODO: with some carriers (in certain countries) you *can* actually
919ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        // tell whether a given number is a mobile phone or not. So in that
920ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        // case we could potentially return false here if the incoming call is
921ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        // from a land line.
922ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
923ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        // If none of the above special cases apply, it's OK to enable the
924ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        // "Respond via SMS" feature.
925ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        return true;
926ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    }
927ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
928ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    List<String> getCannedSmsResponses() {
929ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        return mCannedSmsResponses;
930ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    }
931ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
932ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    /**
93361d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon     * @return True if the call is ringing, else logs the action name.
93461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon     */
93561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    private boolean isRinging(String actionName) {
93661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        if (mState == CallState.RINGING) {
93761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon            return true;
93861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        }
93961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
940f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal        Log.i(this, "Request to %s a non-ringing call %s", actionName, this);
94161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon        return false;
94261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon    }
94361d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon
9448e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad    @SuppressWarnings("rawtypes")
9458e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad    private void decrementAssociatedCallCount(ServiceBinder binder) {
9468e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad        if (binder != null) {
9478e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad            binder.decrementAssociatedCallCount();
9488e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad        }
9498e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad    }
950fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon
951fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    /**
952fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     * Looks up contact information based on the current handle.
953fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     */
954fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    private void startCallerInfoLookup() {
955fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        String number = mHandle == null ? null : mHandle.getSchemeSpecificPart();
956fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon
957fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        mQueryToken++;  // Updated so that previous queries can no longer set the information.
958fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        mCallerInfo = null;
959fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        if (!TextUtils.isEmpty(number)) {
9605ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon            Log.v(this, "Looking up information for: %s.", Log.piiHandle(number));
961fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon            CallerInfoAsyncQuery.startQuery(
962fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon                    mQueryToken,
963fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon                    TelecommApp.getInstance(),
964fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon                    number,
965fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon                    sCallerInfoQueryListener,
966fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon                    this);
967fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        }
968fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    }
969fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon
970fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    /**
97199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon     * Saves the specified caller info if the specified token matches that of the last query
972fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     * that was made.
973fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     *
974fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     * @param callerInfo The new caller information to set.
975fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     * @param token The token used with this query.
976fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon     */
977fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    private void setCallerInfo(CallerInfo callerInfo, int token) {
97899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon        Preconditions.checkNotNull(callerInfo);
97999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon
980fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        if (mQueryToken == token) {
981fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon            mCallerInfo = callerInfo;
9825ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon            Log.i(this, "CallerInfo received for %s: %s", Log.piiHandle(mHandle), callerInfo);
98399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon
98499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            if (mCallerInfo.person_id != 0) {
98599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                Uri personUri =
98699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        ContentUris.withAppendedId(Contacts.CONTENT_URI, mCallerInfo.person_id);
98799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                Log.d(this, "Searching person uri %s for call %s", personUri, this);
98899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                ContactsAsyncHelper.startObtainPhotoAsync(
98999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        token,
99099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        TelecommApp.getInstance(),
99199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        personUri,
99299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        sPhotoLoadListener,
99399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon                        this);
99499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            }
9952174fb56907fddf5680355e097f4425f837983e2Santos Cordon
9962174fb56907fddf5680355e097f4425f837983e2Santos Cordon            processDirectToVoicemail();
99799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon        }
99899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    }
99999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon
100099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    /**
100199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon     * Saves the specified photo information if the specified token matches that of the last query.
100299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon     *
100399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon     * @param photo The photo as a drawable.
100499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon     * @param photoIcon The photo as a small icon.
100599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon     * @param token The token used with this query.
100699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon     */
100799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon    private void setPhoto(Drawable photo, Bitmap photoIcon, int token) {
100899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon        if (mQueryToken == token) {
100999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            mCallerInfo.cachedPhoto = photo;
101099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon            mCallerInfo.cachedPhotoIcon = photoIcon;
1011fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon        }
1012fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon    }
1013ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
1014ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    private void maybeLoadCannedSmsResponses() {
1015ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        if (mIsIncoming && isRespondViaSmsCapable() && !mCannedSmsResponsesLoadingStarted) {
1016ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            Log.d(this, "maybeLoadCannedSmsResponses: starting task to load messages");
1017ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            mCannedSmsResponsesLoadingStarted = true;
1018ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            RespondViaSmsManager.getInstance().loadCannedTextMessages(
1019ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                    new Response<Void, List<String>>() {
1020ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                        @Override
1021ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                        public void onResult(Void request, List<String>... result) {
1022ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                            if (result.length > 0) {
1023ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                                Log.d(this, "maybeLoadCannedSmsResponses: got %s", result[0]);
1024ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                                mCannedSmsResponses = result[0];
1025ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                                for (Listener l : mListeners) {
1026ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                                    l.onCannedSmsResponsesLoaded(Call.this);
1027ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                                }
1028ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                            }
1029ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                        }
1030ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad
1031ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                        @Override
1032ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                        public void onError(Void request, int code, String msg) {
1033ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                            Log.w(Call.this, "Error obtaining canned SMS responses: %d %s", code,
1034ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                                    msg);
1035ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                        }
1036ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad                    }
1037ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            );
1038ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        } else {
1039ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad            Log.d(this, "maybeLoadCannedSmsResponses: doing nothing");
1040ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad        }
1041ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad    }
1042b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati
1043b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati    /**
1044b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati     * Sets speakerphone option on when call begins.
1045b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati     */
1046b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati    public void setStartWithSpeakerphoneOn(boolean startWithSpeakerphone) {
1047b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati        mSpeakerphoneOn = startWithSpeakerphone;
1048b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati    }
1049b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati
1050b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati    /**
1051b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati     * Returns speakerphone option.
1052b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati     *
1053b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati     * @return Whether or not speakerphone should be set automatically when call begins.
1054b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati     */
1055b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati    public boolean getStartWithSpeakerphoneOn() {
1056b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati        return mSpeakerphoneOn;
1057b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati    }
1058e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee
1059e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee    /**
1060e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee     * Sets a call video provider for the call.
1061e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee     */
1062a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen    public void setCallVideoProvider(ICallVideoProvider callVideoProvider) {
1063a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen        mCallVideoProvider = callVideoProvider;
1064a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen        for (Listener l : mListeners) {
1065a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen            l.onCallVideoProviderChanged(Call.this);
1066a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen        }
1067a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen    }
1068a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen
1069a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen    /**
1070a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen     * @return Return the call video Provider binder.
1071a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen     */
1072a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen    public ICallVideoProvider getCallVideoProvider() {
1073a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen        return mCallVideoProvider;
1074e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee    }
1075e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn
1076e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    /**
1077e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     * Returns the features of this call.
1078e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     *
1079e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     * @return The features of this call.
1080e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     */
1081e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    public int getFeatures() {
1082e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn        return mFeatures;
1083e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    }
1084e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn
1085e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    /**
1086e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     * Set the features associated with the call and notify any listeners of the change.
1087e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     *
1088e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     * @param features The features.
1089e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn     */
1090e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    public void setFeatures(int features) {
1091e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn        Log.d(this, "setFeatures: %d", features);
1092e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn        mFeatures = features;
1093e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn        for (Listener l : mListeners) {
1094e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn            l.onFeaturesChanged(Call.this);
1095e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn        }
1096e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn    }
10979f2bed31374a56487f370be01224baf6ce97e8adBen Gilad}
1098