Call.java revision 4a79660c984d54679ad4d2bdc89e224d9c8c375b
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 19905dfba7883666f45a0c6958d8bc6c19d68972d9Sailesh Nepalimport android.content.ComponentName; 2099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.content.ContentUris; 2199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.graphics.Bitmap; 2299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.graphics.drawable.Drawable; 23ce704b9a5d9cf7db30a8c865975c70e5cbc0dc5cSailesh Nepalimport android.net.Uri; 2484fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepalimport android.os.Bundle; 25fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport android.os.Handler; 2699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport android.provider.ContactsContract.Contacts; 27e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepalimport android.telecomm.CallPropertyPresentation; 280b03b4b143234302f098ea18de3c32658b455ecaSantos Cordonimport android.telecomm.CallState; 29c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepalimport android.telecomm.ConnectionRequest; 3033501635c2cd21f40793041eff3b8ce3a5710d49Yorke Leeimport android.telecomm.GatewayInfo; 3198a556026109f816501fa887efdddae78d0c2d65Ihab Awadimport android.telecomm.PhoneAccount; 32ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport android.telecomm.Response; 3335faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepalimport android.telecomm.StatusHints; 34766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordonimport android.telecomm.TelecommConstants; 3579ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordonimport android.telephony.DisconnectCause; 366aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalimport android.telephony.PhoneNumberUtils; 37fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport android.text.TextUtils; 380b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon 39a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chenimport com.android.internal.telecomm.ICallVideoProvider; 40fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport com.android.internal.telephony.CallerInfo; 41fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport com.android.internal.telephony.CallerInfoAsyncQuery; 42fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordonimport com.android.internal.telephony.CallerInfoAsyncQuery.OnQueryCompleteListener; 43ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport com.android.internal.telephony.SmsApplication; 4499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordonimport com.android.telecomm.ContactsAsyncHelper.OnImageLoadCompleteListener; 4561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordonimport com.google.common.base.Preconditions; 46ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport com.google.common.collect.Sets; 4761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 48ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awadimport java.util.Collections; 49a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordonimport java.util.LinkedList; 50a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordonimport java.util.List; 519199078322aea6df26f0d304a28a9a6d040f0717Sailesh Nepalimport java.util.Locale; 52e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepalimport java.util.Objects; 536192561b1f56d7c4e6c650e178e07ba61ad02667Ben Giladimport java.util.Set; 540407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad 552495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad/** 562495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad * Encapsulates all aspects of a given phone call throughout its lifecycle, starting 572495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad * from the time the call intent was received by Telecomm (vs. the time the call was 582495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad * connected etc). 592495d57b5b91f3a39529d8844a49d1be5f18b137Ben Gilad */ 60664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalfinal class Call implements CreateConnectionResponse { 61766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon /** 62766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon * Listener for events on the call. 63766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon */ 64766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon interface Listener { 65766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon void onSuccessfulOutgoingCall(Call call); 665a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal void onFailedOutgoingCall(Call call, int errorCode, String errorMsg); 675a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal void onCancelledOutgoingCall(Call call); 68c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal void onSuccessfulIncomingCall(Call call); 69766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon void onFailedIncomingCall(Call call); 70cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad void onRequestingRingback(Call call, boolean requestingRingback); 71352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton void onPostDialWait(Call call, String remaining); 72e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal void onCallCapabilitiesChanged(Call call); 73a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void onExpiredConferenceCall(Call call); 74a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void onConfirmedConferenceCall(Call call); 75a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void onParentChanged(Call call); 76a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void onChildrenChanged(Call call); 77ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad void onCannedSmsResponsesLoaded(Call call); 78a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen void onCallVideoProviderChanged(Call call); 7964c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon void onCallerInfoChanged(Call call); 807e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal void onAudioModeIsVoipChanged(Call call); 8135faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal void onStatusHintsChanged(Call call); 82e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal void onHandleChanged(Call call); 83e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal void onCallerDisplayNameChanged(Call call); 844a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee void onVideoStateChanged(Call call); 8564c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon } 8664c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon 8764c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon abstract static class ListenerBase implements Listener { 8864c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 8964c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onSuccessfulOutgoingCall(Call call) {} 9064c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 9164c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onFailedOutgoingCall(Call call, int errorCode, String errorMsg) {} 9264c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 9364c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onCancelledOutgoingCall(Call call) {} 9464c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 95c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal public void onSuccessfulIncomingCall(Call call) {} 9664c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 9764c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onFailedIncomingCall(Call call) {} 9864c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 9964c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onRequestingRingback(Call call, boolean requestingRingback) {} 10064c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 10164c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onPostDialWait(Call call, String remaining) {} 10264c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 103e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal public void onCallCapabilitiesChanged(Call call) {} 10464c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 10564c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onExpiredConferenceCall(Call call) {} 10664c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 10764c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onConfirmedConferenceCall(Call call) {} 10864c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 10964c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onParentChanged(Call call) {} 11064c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 11164c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onChildrenChanged(Call call) {} 11264c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 11364c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onCannedSmsResponsesLoaded(Call call) {} 11464c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 11564c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onCallVideoProviderChanged(Call call) {} 11664c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon @Override 11764c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon public void onCallerInfoChanged(Call call) {} 1187e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal @Override 1197e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal public void onAudioModeIsVoipChanged(Call call) {} 12035faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal @Override 12135faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal public void onStatusHintsChanged(Call call) {} 122e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 123e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal public void onHandleChanged(Call call) {} 124e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 125e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal public void onCallerDisplayNameChanged(Call call) {} 1264a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee @Override 1274a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee public void onVideoStateChanged(Call call) {} 128766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 129766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 130fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon private static final OnQueryCompleteListener sCallerInfoQueryListener = 13199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon new OnQueryCompleteListener() { 13299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon /** ${inheritDoc} */ 13399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon @Override 13499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon public void onQueryComplete(int token, Object cookie, CallerInfo callerInfo) { 13599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon if (cookie != null) { 13699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon ((Call) cookie).setCallerInfo(callerInfo, token); 13799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 138fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon } 13999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon }; 14099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon 14199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon private static final OnImageLoadCompleteListener sPhotoLoadListener = 14299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon new OnImageLoadCompleteListener() { 14399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon /** ${inheritDoc} */ 14499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon @Override 14599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon public void onImageLoadComplete( 14699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon int token, Drawable photo, Bitmap photoIcon, Object cookie) { 14799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon if (cookie != null) { 14899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon ((Call) cookie).setPhoto(photo, photoIcon, token); 14999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 15099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 15199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon }; 1520407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad 153664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal private final Runnable mDirectToVoicemailRunnable = new Runnable() { 154664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal @Override 155664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal public void run() { 156664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal processDirectToVoicemail(); 157664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } 158664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal }; 159664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal 160810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal /** True if this is an incoming call. */ 161810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal private final boolean mIsIncoming; 162810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal 1630407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad /** 164664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * The time this call was created. Beyond logging and such, may also be used for bookkeeping 165664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * and specifically for marking certain call attempts as failed attempts. 1660407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad */ 1678c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal private final long mCreationTimeMillis = System.currentTimeMillis(); 1688c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal 169fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon /** The gateway information associated with this call. This stores the original call handle 170fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * that the user is attempting to connect to via the gateway, the actual handle to dial in 171fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * order to connect the call via the gateway, as well as the package name of the gateway 172fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * service. */ 173fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon private final GatewayInfo mGatewayInfo; 174fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon 175b0ba087e1ab7b2b14032a2cb1911f3f4ede05531Sailesh Nepal private PhoneAccount mPhoneAccount; 17677d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen 1772174fb56907fddf5680355e097f4425f837983e2Santos Cordon private final Handler mHandler = new Handler(); 1782174fb56907fddf5680355e097f4425f837983e2Santos Cordon 1798c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal private long mConnectTimeMillis; 1800407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad 18161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon /** The state of the call. */ 18261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon private CallState mState; 18361d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 18461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon /** The handle with which to establish this call. */ 185ce704b9a5d9cf7db30a8c865975c70e5cbc0dc5cSailesh Nepal private Uri mHandle; 18661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 187e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal /** The {@link CallPropertyPresentation} that controls how the handle is shown. */ 188e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal private int mHandlePresentation; 189e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 190e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal /** The caller display name (CNAP) set by the connection service. */ 191e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal private String mCallerDisplayName; 192e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 193e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal /** The {@link CallPropertyPresentation} that controls how the caller display name is shown. */ 194e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal private int mCallerDisplayNamePresentation; 195e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 1960407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad /** 197c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal * The connection service which is attempted or already connecting this call. 198681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon */ 199c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal private ConnectionServiceWrapper mConnectionService; 2006192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 2016aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal private boolean mIsEmergencyCall; 2026aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal 203b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati private boolean mSpeakerphoneOn; 204b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati 205c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn private int mVideoState; 206c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn 2076192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 20879ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon * Disconnect cause for the call. Only valid if the state of the call is DISCONNECTED. 20979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon * See {@link android.telephony.DisconnectCause}. 21079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon */ 2118c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal private int mDisconnectCause = DisconnectCause.NOT_VALID; 21279ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon 21379ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon /** 214c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal * Additional disconnect information provided by the connection service. 21579ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon */ 21679ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon private String mDisconnectMessage; 21779ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon 218c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal /** Info used by the connection services. */ 2198c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal private Bundle mExtras = Bundle.EMPTY; 22084fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal 221766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon /** Set of listeners on this call. */ 222766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon private Set<Listener> mListeners = Sets.newHashSet(); 223766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 224664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal private CreateConnectionProcessor mCreateConnectionProcessor; 225682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon 226fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon /** Caller information retrieved from the latest contact query. */ 227fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon private CallerInfo mCallerInfo; 228fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon 229fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon /** The latest token used with a contact info query. */ 230fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon private int mQueryToken = 0; 231fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon 232cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad /** Whether this call is requesting that Telecomm play the ringback tone on its behalf. */ 233cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad private boolean mRequestingRingback = false; 234cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad 235c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal /** Whether direct-to-voicemail query is pending. */ 236c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal private boolean mDirectToVoicemailQueryPending; 2372174fb56907fddf5680355e097f4425f837983e2Santos Cordon 238e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal private int mCallCapabilities; 239a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 240a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon private boolean mIsConference = false; 241a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 242a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon private Call mParentCall = null; 243a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 244a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon private List<Call> mChildCalls = new LinkedList<>(); 245a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 246ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad /** Set of text message responses allowed for this call, if applicable. */ 247ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad private List<String> mCannedSmsResponses = Collections.EMPTY_LIST; 248ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 249ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad /** Whether an attempt has been made to load the text message responses. */ 250ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad private boolean mCannedSmsResponsesLoadingStarted = false; 251ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 252a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen private ICallVideoProvider mCallVideoProvider; 253a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen 2547e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal private boolean mAudioModeIsVoip; 25535faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal private StatusHints mStatusHints; 256664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal private final ConnectionServiceRepository mRepository; 2577e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal 2588c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal /** 2590407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * Persists the specified parameters and initializes the new instance. 2600407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * 2610407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * @param handle The handle to dial. 26233501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee * @param gatewayInfo Gateway information to use for the call. 26398a556026109f816501fa887efdddae78d0c2d65Ihab Awad * @param account Account information to use for the call. 264810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal * @param isIncoming True if this is an incoming call. 2650407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad */ 266664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal Call( 267664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal ConnectionServiceRepository repository, 268664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal Uri handle, 269664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal GatewayInfo gatewayInfo, 270664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal PhoneAccount account, 271664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal boolean isIncoming, 272664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal boolean isConference) { 273a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon mState = isConference ? CallState.ACTIVE : CallState.NEW; 274664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mRepository = repository; 275e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal setHandle(handle, CallPropertyPresentation.ALLOWED); 27633501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee mGatewayInfo = gatewayInfo; 277b0ba087e1ab7b2b14032a2cb1911f3f4ede05531Sailesh Nepal mPhoneAccount = account; 278810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal mIsIncoming = isIncoming; 279a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon mIsConference = isConference; 280ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad maybeLoadCannedSmsResponses(); 2810407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad } 2820407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad 283766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon void addListener(Listener listener) { 284766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon mListeners.add(listener); 285766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 286766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 287766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon void removeListener(Listener listener) { 288766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon mListeners.remove(listener); 289766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 290766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 29161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon /** {@inheritDoc} */ 29261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon @Override public String toString() { 2934538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal String component = null; 294c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal if (mConnectionService != null && mConnectionService.getComponentName() != null) { 295c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal component = mConnectionService.getComponentName().flattenToShortString(); 2964538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal } 2974538f01647fa207b41fb7e481cc180e67fd391deSailesh Nepal return String.format(Locale.US, "[%s, %s, %s]", mState, component, Log.piiHandle(mHandle)); 29861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 29961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 3000b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon CallState getState() { 301a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (mIsConference) { 302a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (!mChildCalls.isEmpty()) { 303a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon // If we have child calls, just return the child call. 304a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon return mChildCalls.get(0).getState(); 305a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 306a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon return CallState.ACTIVE; 307a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } else { 308a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon return mState; 309a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 3100b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon } 3110b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon 3120b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon /** 3130b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon * Sets the call state. Although there exists the notion of appropriate state transitions 3140b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon * (see {@link CallState}), in practice those expectations break down when cellular systems 3150b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon * misbehave and they do this very often. The result is that we do not enforce state transitions 3160b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon * and instead keep the code resilient to unexpected state changes. 3170b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon */ 318810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal void setState(CallState newState) { 31979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon Preconditions.checkState(newState != CallState.DISCONNECTED || 32079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon mDisconnectCause != DisconnectCause.NOT_VALID); 321810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal if (mState != newState) { 322810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal Log.v(this, "setState %s -> %s", mState, newState); 323810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal mState = newState; 324ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad maybeLoadCannedSmsResponses(); 325810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal } 3260b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon } 3270b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon 328cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad void setRequestingRingback(boolean requestingRingback) { 329cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad mRequestingRingback = requestingRingback; 330cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad for (Listener l : mListeners) { 331cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad l.onRequestingRingback(this, mRequestingRingback); 332cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad } 333cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad } 334cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad 335cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad boolean isRequestingRingback() { 336cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad return mRequestingRingback; 337cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad } 338cb387ac1bb278de62e352b363cb38339629a61f5Ihab Awad 339ce704b9a5d9cf7db30a8c865975c70e5cbc0dc5cSailesh Nepal Uri getHandle() { 3400bf5b912285e328a8f5eeec158d6caf17845b9f8Ben Gilad return mHandle; 3410bf5b912285e328a8f5eeec158d6caf17845b9f8Ben Gilad } 3420bf5b912285e328a8f5eeec158d6caf17845b9f8Ben Gilad 343e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal int getHandlePresentation() { 344e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal return mHandlePresentation; 345e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 346e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 347e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal void setHandle(Uri handle, int presentation) { 348e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal if (!Objects.equals(handle, mHandle) || presentation != mHandlePresentation) { 349fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon mHandle = handle; 350e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal mHandlePresentation = presentation; 351fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon mIsEmergencyCall = mHandle != null && PhoneNumberUtils.isLocalEmergencyNumber( 3526625545769bd9c5aa15b7e1ee9402f75ad799e81Yorke Lee TelecommApp.getInstance(), mHandle.getSchemeSpecificPart()); 353fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon startCallerInfoLookup(); 354e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal for (Listener l : mListeners) { 355e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal l.onHandleChanged(this); 356e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 357e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 358e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 359e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 360e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal String getCallerDisplayName() { 361e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal return mCallerDisplayName; 362e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 363e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 364e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal int getCallerDisplayNamePresentation() { 365e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal return mCallerDisplayNamePresentation; 366e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 367e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 368e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal void setCallerDisplayName(String callerDisplayName, int presentation) { 369e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal if (!TextUtils.equals(callerDisplayName, mCallerDisplayName) || 370e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal presentation != mCallerDisplayNamePresentation) { 371e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal mCallerDisplayName = callerDisplayName; 372e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal mCallerDisplayNamePresentation = presentation; 373e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal for (Listener l : mListeners) { 374e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal l.onCallerDisplayNameChanged(this); 375e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 376fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon } 3776aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal } 3786aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal 37999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon String getName() { 38099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon return mCallerInfo == null ? null : mCallerInfo.name; 38199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 38299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon 38399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon Bitmap getPhotoIcon() { 38499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon return mCallerInfo == null ? null : mCallerInfo.cachedPhotoIcon; 38599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 38699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon 38799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon Drawable getPhoto() { 38899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon return mCallerInfo == null ? null : mCallerInfo.cachedPhoto; 38999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 39099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon 39179ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon /** 39279ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon * @param disconnectCause The reason for the disconnection, any of 39379ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon * {@link android.telephony.DisconnectCause}. 394905dfba7883666f45a0c6958d8bc6c19d68972d9Sailesh Nepal * @param disconnectMessage Optional message about the disconnect. 39579ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon */ 39679ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon void setDisconnectCause(int disconnectCause, String disconnectMessage) { 39779ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon // TODO: Consider combining this method with a setDisconnected() method that is totally 39879ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon // separate from setState. 39979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon mDisconnectCause = disconnectCause; 40079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon mDisconnectMessage = disconnectMessage; 40179ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon } 40279ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon 40379ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon int getDisconnectCause() { 40479ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon return mDisconnectCause; 40579ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon } 40679ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon 40779ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon String getDisconnectMessage() { 40879ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon return mDisconnectMessage; 40979ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon } 41079ff2bcdbdf1c28f229f4acec9433beb1cd7a57eSantos Cordon 4116aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal boolean isEmergencyCall() { 4126aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal return mIsEmergencyCall; 41361d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 41461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 41533501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee /** 41633501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee * @return The original handle this call is associated with. In-call services should use this 41733501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee * handle when indicating in their UI the handle that is being called. 41833501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee */ 41933501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee public Uri getOriginalHandle() { 42033501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee if (mGatewayInfo != null && !mGatewayInfo.isEmpty()) { 42133501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee return mGatewayInfo.getOriginalHandle(); 42233501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee } 42333501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee return getHandle(); 42433501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee } 42533501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee 42633501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee GatewayInfo getGatewayInfo() { 42733501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee return mGatewayInfo; 42833501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee } 42933501635c2cd21f40793041eff3b8ce3a5710d49Yorke Lee 430b0ba087e1ab7b2b14032a2cb1911f3f4ede05531Sailesh Nepal PhoneAccount getPhoneAccount() { 431b0ba087e1ab7b2b14032a2cb1911f3f4ede05531Sailesh Nepal return mPhoneAccount; 43277d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen } 43377d2d0e90bc2a67d526743b8e32f920a0d755fbaNancy Chen 434810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal boolean isIncoming() { 435810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal return mIsIncoming; 436810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal } 437810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal 4380407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad /** 4390407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad * @return The "age" of this call object in milliseconds, which typically also represents the 4408c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal * period since this call was added to the set pending outgoing calls, see 4418c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal * mCreationTimeMillis. 4420407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad */ 4438c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal long getAgeMillis() { 4448c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal return System.currentTimeMillis() - mCreationTimeMillis; 4450407fb2c5a8358cfae92bbd6f8cdc103d66c7b13Ben Gilad } 4460b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon 447f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee /** 448f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee * @return The time when this call object was created and added to the set of pending outgoing 449f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee * calls. 450f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee */ 4518c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal long getCreationTimeMillis() { 4528c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal return mCreationTimeMillis; 4538c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 4548c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal 4558c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal long getConnectTimeMillis() { 4568c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal return mConnectTimeMillis; 4578c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 4588c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal 4598c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal void setConnectTimeMillis(long connectTimeMillis) { 4608c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal mConnectTimeMillis = connectTimeMillis; 461f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee } 462f98fb5790ed62a3d4893362554f8d251c74d0ecdYorke Lee 463e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal int getCallCapabilities() { 464e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal return mCallCapabilities; 465a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 466a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 467e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal void setCallCapabilities(int callCapabilities) { 468e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal if (mCallCapabilities != callCapabilities) { 469e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal mCallCapabilities = callCapabilities; 470a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon for (Listener l : mListeners) { 471e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal l.onCallCapabilitiesChanged(this); 472a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 473a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 474a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 475a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 476a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon Call getParentCall() { 477a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon return mParentCall; 478a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 479a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 480a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon List<Call> getChildCalls() { 481a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon return mChildCalls; 482a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 483a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 484c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal ConnectionServiceWrapper getConnectionService() { 485c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal return mConnectionService; 486681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon } 487681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon 488c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal void setConnectionService(ConnectionServiceWrapper service) { 489c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Preconditions.checkNotNull(service); 4908e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 491c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal clearConnectionService(); 4928e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 493c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal service.incrementAssociatedCallCount(); 494c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService = service; 495c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.addCall(this); 496681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon } 497681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon 498681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon /** 499c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal * Clears the associated connection service. 500681663d17b6d92b604526a54b196fa88f25b6957Santos Cordon */ 501c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal void clearConnectionService() { 502c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal if (mConnectionService != null) { 503c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal ConnectionServiceWrapper serviceTemp = mConnectionService; 504c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService = null; 505c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal serviceTemp.removeCall(this); 506c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 507c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon // Decrementing the count can cause the service to unbind, which itself can trigger the 508c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon // service-death code. Since the service death code tries to clean up any associated 509c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon // calls, we need to make sure to remove that information (e.g., removeCall()) before 510c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon // we decrement. Technically, invoking removeCall() prior to decrementing is all that is 511c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // necessary, but cleaning up mConnectionService prior to triggering an unbind is good 512c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // to do. 513c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal decrementAssociatedCallCount(serviceTemp); 514adee12dd6b3e85ce3ae419329226c9aa72c184fcYorke Lee } 5158e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 5168e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 517664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal private void processDirectToVoicemail() { 518c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal if (mDirectToVoicemailQueryPending) { 5192174fb56907fddf5680355e097f4425f837983e2Santos Cordon if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) { 5202174fb56907fddf5680355e097f4425f837983e2Santos Cordon Log.i(this, "Directing call to voicemail: %s.", this); 5212174fb56907fddf5680355e097f4425f837983e2Santos Cordon // TODO(santoscordon): Once we move State handling from CallsManager to Call, we 5222174fb56907fddf5680355e097f4425f837983e2Santos Cordon // will not need to set RINGING state prior to calling reject. 5232174fb56907fddf5680355e097f4425f837983e2Santos Cordon setState(CallState.RINGING); 524ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad reject(false, null); 5252174fb56907fddf5680355e097f4425f837983e2Santos Cordon } else { 5262174fb56907fddf5680355e097f4425f837983e2Santos Cordon // TODO(santoscordon): Make this class (not CallsManager) responsible for changing 5272174fb56907fddf5680355e097f4425f837983e2Santos Cordon // the call state to RINGING. 5282174fb56907fddf5680355e097f4425f837983e2Santos Cordon 5292174fb56907fddf5680355e097f4425f837983e2Santos Cordon // TODO(santoscordon): Replace this with state transition to RINGING. 5302174fb56907fddf5680355e097f4425f837983e2Santos Cordon for (Listener l : mListeners) { 531c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal l.onSuccessfulIncomingCall(this); 5322174fb56907fddf5680355e097f4425f837983e2Santos Cordon } 5332174fb56907fddf5680355e097f4425f837983e2Santos Cordon } 534766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 535c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mDirectToVoicemailQueryPending = false; 536766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 537766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 538766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 539766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon /** 540664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * Starts the create connection sequence. Upon completion, there should exist an active 541664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * connection through a connection service (or the call will have failed). 542766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon */ 543664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal void startCreateConnection() { 544664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal Preconditions.checkState(mCreateConnectionProcessor == null); 545664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this); 546664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mCreateConnectionProcessor.process(); 547766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 548766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 5495a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal @Override 550664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal public void handleCreateConnectionSuccessful(ConnectionRequest request) { 551664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mCreateConnectionProcessor = null; 552664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mPhoneAccount = request.getAccount(); 553664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal 554664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal if (mIsIncoming) { 555664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal // We do not handle incoming calls immediately when they are verified by the connection 556664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal // service. We allow the caller-info-query code to execute first so that we can read the 557664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal // direct-to-voicemail property before deciding if we want to show the incoming call to 558664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal // the user or if we want to reject the call. 559664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mDirectToVoicemailQueryPending = true; 560664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal 561664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal // Setting the handle triggers the caller info lookup code. 562664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal setHandle(request.getHandle(), request.getHandlePresentation()); 563664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal 564664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal // Timeout the direct-to-voicemail lookup execution so that we dont wait too long before 565664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal // showing the user the incoming call screen. 566664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis()); 567664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } else { 568664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal for (Listener l : mListeners) { 569664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal l.onSuccessfulOutgoingCall(this); 570664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } 571766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 5725a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal } 5735a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal 5745a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal @Override 575664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal public void handleCreateConnectionFailed(int code, String msg) { 576664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mCreateConnectionProcessor = null; 577664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal if (mIsIncoming) { 578664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal clearConnectionService(); 579664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal setDisconnectCause(code, null); 580664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal setState(CallState.DISCONNECTED); 581664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal 582664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]); 583664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal for (int i = 0; i < listeners.length; i++) { 584664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal listeners[i].onFailedIncomingCall(this); 585664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } 586664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } else { 587664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]); 588664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal for (int i = 0; i < listeners.length; i++) { 589664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal listeners[i].onFailedOutgoingCall(this, code, msg); 590664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } 591664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal clearConnectionService(); 5925a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal } 593766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 594766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 5955a73b03be0a2a929cf9974578445b90f773937b4Sailesh Nepal @Override 596664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal public void handleCreateConnectionCancelled() { 597664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mCreateConnectionProcessor = null; 598664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal if (mIsIncoming) { 599664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal clearConnectionService(); 600664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED, null); 601664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal setState(CallState.DISCONNECTED); 602664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal 603664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]); 604664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal for (int i = 0; i < listeners.length; i++) { 605664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal listeners[i].onFailedIncomingCall(this); 606664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } 607664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } else { 608664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]); 609664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal for (int i = 0; i < listeners.length; i++) { 610664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal listeners[i].onCancelledOutgoingCall(this); 611664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal } 612664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal clearConnectionService(); 613766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 614766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon } 615766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 616766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon /** 61774549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad * Plays the specified DTMF tone. 61874549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad */ 61974549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad void playDtmfTone(char digit) { 620c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal if (mConnectionService == null) { 621c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Log.w(this, "playDtmfTone() request on a call without a connection service."); 62274549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad } else { 623c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Log.i(this, "Send playDtmfTone to connection service for call %s", this); 624c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.playDtmfTone(this, digit); 62574549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad } 62674549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad } 62774549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad 62874549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad /** 62974549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad * Stops playing any currently playing DTMF tone. 63074549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad */ 63174549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad void stopDtmfTone() { 632c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal if (mConnectionService == null) { 633c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Log.w(this, "stopDtmfTone() request on a call without a connectino service."); 63474549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad } else { 635c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Log.i(this, "Send stopDtmfTone to connection service for call %s", this); 636c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.stopDtmfTone(this); 63774549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad } 63874549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad } 63974549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad 64074549ec95acf0d2ddbe4feca91c6febdf8008074Ihab Awad /** 641c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal * Attempts to disconnect the call through the connection service. 642049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon */ 643049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon void disconnect() { 644766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon if (mState == CallState.NEW) { 645682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon Log.v(this, "Aborting call %s", this); 646682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon abort(); 64774d420be72fa30735fe9b7a25715f6db046c0398Santos Cordon } else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) { 648c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Preconditions.checkNotNull(mConnectionService); 649766d04f7cad00b0b09e39db6835676354acd2cdaSantos Cordon 650c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Log.i(this, "Send disconnect to connection service for call: %s", this); 651c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // The call isn't officially disconnected until the connection service confirms that the 652c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // call was actually disconnected. Only then is the association between call and 653c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // connection service severed, see {@link CallsManager#markCallAsDisconnected}. 654c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.disconnect(this); 655049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 656049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 657049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon 658682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon void abort() { 659664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal if (mCreateConnectionProcessor != null) { 660664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal mCreateConnectionProcessor.abort(); 661682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon } 662682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon } 663682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon 6640b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon /** 66561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon * Answers the call if it is ringing. 66661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon */ 66761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon void answer() { 668c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Preconditions.checkNotNull(mConnectionService); 66961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 67061d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon // Check to verify that the call is still in the ringing state. A call can change states 67161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon // between the time the user hits 'answer' and Telecomm receives the command. 67261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon if (isRinging("answer")) { 673c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // At this point, we are asking the connection service to answer but we don't assume 674c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // that it will work. Instead, we wait until confirmation from the connectino service 675c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // that the call is in a non-RINGING state before changing the UI. See 676c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // {@link ConnectionServiceAdapter#setActive} and other set* methods. 677c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.answer(this); 67861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 67961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 68061d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 68161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon /** 68261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon * Rejects the call if it is ringing. 683ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * 684ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * @param rejectWithMessage Whether to send a text message as part of the call rejection. 685ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * @param textMessage An optional text message to send as part of the rejection. 68661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon */ 687ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad void reject(boolean rejectWithMessage, String textMessage) { 688c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Preconditions.checkNotNull(mConnectionService); 68961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 69061d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon // Check to verify that the call is still in the ringing state. A call can change states 69161d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon // between the time the user hits 'reject' and Telecomm receives the command. 69261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon if (isRinging("reject")) { 693c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.reject(this); 69461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 69561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 69661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 69761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon /** 698cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee * Puts the call on hold if it is currently active. 699cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee */ 700cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee void hold() { 701c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Preconditions.checkNotNull(mConnectionService); 702cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee 703cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee if (mState == CallState.ACTIVE) { 704c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.hold(this); 705cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee } 706cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee } 707cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee 708cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee /** 709cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee * Releases the call from hold if it is currently active. 710cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee */ 711cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee void unhold() { 712c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Preconditions.checkNotNull(mConnectionService); 713cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee 714cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee if (mState == CallState.ON_HOLD) { 715c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.unhold(this); 716571f0737002251f09b9ef696dc8b4c9ce02abbaeSantos Cordon } 7170b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon } 7180b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon 7196aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal /** Checks if this is a live call or not. */ 7206aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal boolean isAlive() { 7216aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal switch (mState) { 7226aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal case NEW: 7236aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal case RINGING: 7246aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal case DISCONNECTED: 7256aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal case ABORTED: 7266aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal return false; 7276aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal default: 7286aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal return true; 7296aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal } 7306aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal } 7316aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal 73240f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon boolean isActive() { 73384bfe47a2447c4983bcc58468000f04683eec55bIhab Awad return mState == CallState.ACTIVE; 73440f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon } 73540f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon 73684fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal Bundle getExtras() { 73784fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal return mExtras; 73884fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal } 73984fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal 74084fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal void setExtras(Bundle extras) { 74184fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal mExtras = extras; 74284fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal } 74384fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepal 7445ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon Uri getRingtone() { 7455ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon return mCallerInfo == null ? null : mCallerInfo.contactRingtoneUri; 7465ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon } 7475ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon 748352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton void onPostDialWait(String remaining) { 749352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton for (Listener l : mListeners) { 750352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton l.onPostDialWait(this, remaining); 751352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton } 752352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton } 753352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton 754352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton void postDialContinue(boolean proceed) { 755c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.onPostDialContinue(this, proceed); 756352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton } 757352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton 75877da19ea28b8753d439660b4352c1bf914f63a92Sailesh Nepal void phoneAccountClicked() { 759c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.onPhoneAccountClicked(this); 76077da19ea28b8753d439660b4352c1bf914f63a92Sailesh Nepal } 76177da19ea28b8753d439660b4352c1bf914f63a92Sailesh Nepal 762a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void conferenceInto(Call conferenceCall) { 763c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal if (mConnectionService == null) { 764c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Log.w(this, "conference requested on a call without a connection service."); 765a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } else { 766c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal mConnectionService.conference(conferenceCall, this); 767a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 768a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 769a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 770a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void expireConference() { 771a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon // The conference call expired before we got a confirmation of the conference from the 772c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal // connection service...so start shutting down. 773c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal clearConnectionService(); 774a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon for (Listener l : mListeners) { 775a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon l.onExpiredConferenceCall(this); 776a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 777a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 778a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 779a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void confirmConference() { 780a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon Log.v(this, "confirming Conf call %s", mListeners); 781a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon for (Listener l : mListeners) { 782a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon l.onConfirmedConferenceCall(this); 783a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 784a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 785a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 786a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void splitFromConference() { 787a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon // TODO(santoscordon): todo 788a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 789a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 790e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal void swapWithBackgroundCall() { 791e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal mConnectionService.swapWithBackgroundCall(this); 792e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 793e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 794a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon void setParentCall(Call parentCall) { 795a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (parentCall == this) { 796a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon Log.e(this, new Exception(), "setting the parent to self"); 797a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon return; 798a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 799a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon Preconditions.checkState(parentCall == null || mParentCall == null); 800a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 801a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon Call oldParent = mParentCall; 802a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (mParentCall != null) { 803a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon mParentCall.removeChildCall(this); 804a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 805a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon mParentCall = parentCall; 806a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (mParentCall != null) { 807a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon mParentCall.addChildCall(this); 808a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 809a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 810a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon for (Listener l : mListeners) { 811a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon l.onParentChanged(this); 812a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 813a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 814a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 815a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon private void addChildCall(Call call) { 816a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (!mChildCalls.contains(call)) { 817a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon mChildCalls.add(call); 818a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 819a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon for (Listener l : mListeners) { 820a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon l.onChildrenChanged(this); 821a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 822a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 823a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 824a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 825a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon private void removeChildCall(Call call) { 826a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (mChildCalls.remove(call)) { 827a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon for (Listener l : mListeners) { 828a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon l.onChildrenChanged(this); 829a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 830a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 831a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 832a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 8330b03b4b143234302f098ea18de3c32658b455ecaSantos Cordon /** 834ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * Return whether the user can respond to this {@code Call} via an SMS message. 835ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * 836ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * @return true if the "Respond via SMS" feature should be enabled 837ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * for this incoming call. 838ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * 839ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * The general rule is that we *do* allow "Respond via SMS" except for 840ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * the few (relatively rare) cases where we know for sure it won't 841ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * work, namely: 842ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * - a bogus or blank incoming number 843ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * - a call from a SIP address 844ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * - a "call presentation" that doesn't allow the number to be revealed 845ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * 846ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * In all other cases, we allow the user to respond via SMS. 847ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * 848ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * Note that this behavior isn't perfect; for example we have no way 849ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * to detect whether the incoming call is from a landline (with most 850ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * networks at least), so we still enable this feature even though 851ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad * SMSes to that number will silently fail. 852ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad */ 853ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad boolean isRespondViaSmsCapable() { 854ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad if (mState != CallState.RINGING) { 855ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad return false; 856ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 857ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 858ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad if (getHandle() == null) { 859ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // No incoming number known or call presentation is "PRESENTATION_RESTRICTED", in 860ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // other words, the user should not be able to see the incoming phone number. 861ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad return false; 862ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 863ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 864ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad if (PhoneNumberUtils.isUriNumber(getHandle().toString())) { 865ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // The incoming number is actually a URI (i.e. a SIP address), 866ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // not a regular PSTN phone number, and we can't send SMSes to 867ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // SIP addresses. 868ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // (TODO: That might still be possible eventually, though. Is 869ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // there some SIP-specific equivalent to sending a text message?) 870ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad return false; 871ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 872ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 873ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // Is there a valid SMS application on the phone? 874ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad if (SmsApplication.getDefaultRespondViaMessageApplication(TelecommApp.getInstance(), 875ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad true /*updateIfNeeded*/) == null) { 876ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad return false; 877ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 878ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 879ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // TODO: with some carriers (in certain countries) you *can* actually 880ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // tell whether a given number is a mobile phone or not. So in that 881ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // case we could potentially return false here if the incoming call is 882ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // from a land line. 883ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 884ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // If none of the above special cases apply, it's OK to enable the 885ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad // "Respond via SMS" feature. 886ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad return true; 887ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 888ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 889ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad List<String> getCannedSmsResponses() { 890ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad return mCannedSmsResponses; 891ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 892ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 893ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad /** 89461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon * @return True if the call is ringing, else logs the action name. 89561d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon */ 89661d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon private boolean isRinging(String actionName) { 89761d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon if (mState == CallState.RINGING) { 89861d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon return true; 89961d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 90061d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 901f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal Log.i(this, "Request to %s a non-ringing call %s", actionName, this); 90261d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon return false; 90361d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon } 90461d0f70cf45036f9cdeb41b96538f792b7c9764bSantos Cordon 9058e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad @SuppressWarnings("rawtypes") 9068e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad private void decrementAssociatedCallCount(ServiceBinder binder) { 9078e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad if (binder != null) { 9088e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad binder.decrementAssociatedCallCount(); 9098e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 9108e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 911fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon 912fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon /** 913fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * Looks up contact information based on the current handle. 914fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon */ 915fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon private void startCallerInfoLookup() { 916fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon String number = mHandle == null ? null : mHandle.getSchemeSpecificPart(); 917fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon 918fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon mQueryToken++; // Updated so that previous queries can no longer set the information. 919fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon mCallerInfo = null; 920fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon if (!TextUtils.isEmpty(number)) { 9215ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon Log.v(this, "Looking up information for: %s.", Log.piiHandle(number)); 922fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon CallerInfoAsyncQuery.startQuery( 923fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon mQueryToken, 924fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon TelecommApp.getInstance(), 925fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon number, 926fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon sCallerInfoQueryListener, 927fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon this); 928fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon } 929fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon } 930fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon 931fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon /** 93299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon * Saves the specified caller info if the specified token matches that of the last query 933fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * that was made. 934fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * 935fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * @param callerInfo The new caller information to set. 936fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon * @param token The token used with this query. 937fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon */ 938fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon private void setCallerInfo(CallerInfo callerInfo, int token) { 93999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon Preconditions.checkNotNull(callerInfo); 94099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon 941fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon if (mQueryToken == token) { 942fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon mCallerInfo = callerInfo; 9435ba7f27491e287f39a999ddd3d1ed6a7bad78272Santos Cordon Log.i(this, "CallerInfo received for %s: %s", Log.piiHandle(mHandle), callerInfo); 94499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon 945a1662d0ae89d9fb514a5ac68cbc76660e34dae00Makoto Onuki if (mCallerInfo.contactDisplayPhotoUri != null) { 946a1662d0ae89d9fb514a5ac68cbc76660e34dae00Makoto Onuki Log.d(this, "Searching person uri %s for call %s", 947a1662d0ae89d9fb514a5ac68cbc76660e34dae00Makoto Onuki mCallerInfo.contactDisplayPhotoUri, this); 94899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon ContactsAsyncHelper.startObtainPhotoAsync( 94999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon token, 95099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon TelecommApp.getInstance(), 951a1662d0ae89d9fb514a5ac68cbc76660e34dae00Makoto Onuki mCallerInfo.contactDisplayPhotoUri, 95299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon sPhotoLoadListener, 95399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon this); 954a1662d0ae89d9fb514a5ac68cbc76660e34dae00Makoto Onuki // Do not call onCallerInfoChanged yet in this case. We call it in setPhoto(). 95564c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon } else { 95664c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon for (Listener l : mListeners) { 95764c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon l.onCallerInfoChanged(this); 95864c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon } 95999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 9602174fb56907fddf5680355e097f4425f837983e2Santos Cordon 9612174fb56907fddf5680355e097f4425f837983e2Santos Cordon processDirectToVoicemail(); 96299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 96399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon } 96499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon 9656f3f7affb13e93cb70868d3114f02f1ed593194eYorke Lee CallerInfo getCallerInfo() { 9666f3f7affb13e93cb70868d3114f02f1ed593194eYorke Lee return mCallerInfo; 9676f3f7affb13e93cb70868d3114f02f1ed593194eYorke Lee } 9686f3f7affb13e93cb70868d3114f02f1ed593194eYorke Lee 96999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon /** 97099c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon * Saves the specified photo information if the specified token matches that of the last query. 97199c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon * 97299c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon * @param photo The photo as a drawable. 97399c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon * @param photoIcon The photo as a small icon. 97499c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon * @param token The token used with this query. 97599c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon */ 97699c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon private void setPhoto(Drawable photo, Bitmap photoIcon, int token) { 97799c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon if (mQueryToken == token) { 97899c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon mCallerInfo.cachedPhoto = photo; 97999c8a6fc0ae4c50878a748280a0ae2d8dd6b040eSantos Cordon mCallerInfo.cachedPhotoIcon = photoIcon; 98064c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon 98164c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon for (Listener l : mListeners) { 98264c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon l.onCallerInfoChanged(this); 98364c7e965de50c6321415942ab4a84d22514b39a1Santos Cordon } 984fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon } 985fd71f4adb6f04ab485563133f5ccf541de04b002Santos Cordon } 986ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 987ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad private void maybeLoadCannedSmsResponses() { 988ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad if (mIsIncoming && isRespondViaSmsCapable() && !mCannedSmsResponsesLoadingStarted) { 989ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad Log.d(this, "maybeLoadCannedSmsResponses: starting task to load messages"); 990ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad mCannedSmsResponsesLoadingStarted = true; 991ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad RespondViaSmsManager.getInstance().loadCannedTextMessages( 992ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad new Response<Void, List<String>>() { 993ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad @Override 994ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad public void onResult(Void request, List<String>... result) { 995ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad if (result.length > 0) { 996ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad Log.d(this, "maybeLoadCannedSmsResponses: got %s", result[0]); 997ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad mCannedSmsResponses = result[0]; 998ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad for (Listener l : mListeners) { 999ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad l.onCannedSmsResponsesLoaded(Call.this); 1000ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 1001ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 1002ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 1003ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 1004ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad @Override 1005ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad public void onError(Void request, int code, String msg) { 1006ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad Log.w(Call.this, "Error obtaining canned SMS responses: %d %s", code, 1007ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad msg); 1008ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 1009ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 1010ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad ); 1011ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } else { 1012ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad Log.d(this, "maybeLoadCannedSmsResponses: doing nothing"); 1013ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 1014ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 1015b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati 1016b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati /** 1017b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati * Sets speakerphone option on when call begins. 1018b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati */ 1019b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati public void setStartWithSpeakerphoneOn(boolean startWithSpeakerphone) { 1020b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati mSpeakerphoneOn = startWithSpeakerphone; 1021b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati } 1022b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati 1023b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati /** 1024b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati * Returns speakerphone option. 1025b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati * 1026b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati * @return Whether or not speakerphone should be set automatically when call begins. 1027b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati */ 1028b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati public boolean getStartWithSpeakerphoneOn() { 1029b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati return mSpeakerphoneOn; 1030b7157e9f7dbf151c4c6ff4ebcc171632af00616eSai Cheemalapati } 1031e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee 1032e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee /** 1033e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee * Sets a call video provider for the call. 1034e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee */ 1035a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen public void setCallVideoProvider(ICallVideoProvider callVideoProvider) { 1036a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen mCallVideoProvider = callVideoProvider; 1037a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen for (Listener l : mListeners) { 1038a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen l.onCallVideoProviderChanged(Call.this); 1039a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen } 1040a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen } 1041a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen 1042a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen /** 1043a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen * @return Return the call video Provider binder. 1044a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen */ 1045a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen public ICallVideoProvider getCallVideoProvider() { 1046a65d41fb134e323ab43c3f9454313b262959b1d0Nancy Chen return mCallVideoProvider; 1047e9a776560dfe6f000cfc0dc1ea36c0f37d937f53Andrew Lee } 1048e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn 1049e19cc005ddbff5313d6f7288587630b2410d005cTyler Gunn /** 1050c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * The current video state for the call. 1051c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * Valid values: {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY}, 1052c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL}, 1053c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_TX_ENABLED}, 1054c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_RX_ENABLED}. 1055c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * 1056c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * @return True if video is enabled. 1057c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn */ 1058c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn public int getVideoState() { 1059c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn return mVideoState; 1060c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn } 1061c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn 1062c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn /** 1063c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * At the start of the call, determines the desired video state for the call. 1064c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * Valid values: {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY}, 1065c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL}, 1066c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_TX_ENABLED}, 1067c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_RX_ENABLED}. 1068c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * 1069c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn * @param videoState The desired video state for the call. 1070c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn */ 1071c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn public void setVideoState(int videoState) { 1072c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn mVideoState = videoState; 10734a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee for (Listener l : mListeners) { 10744a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee l.onVideoStateChanged(this); 10754a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee } 1076c4abd91cd8a67b530ebafe146af10136db8e6605Tyler Gunn } 10777e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal 10787e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal public boolean getAudioModeIsVoip() { 10797e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal return mAudioModeIsVoip; 10807e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal } 10817e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal 10827e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal public void setAudioModeIsVoip(boolean audioModeIsVoip) { 10837e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal mAudioModeIsVoip = audioModeIsVoip; 10847e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal for (Listener l : mListeners) { 108535faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal l.onAudioModeIsVoipChanged(this); 108635faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal } 108735faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal } 108835faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal 108935faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal public StatusHints getStatusHints() { 109035faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal return mStatusHints; 109135faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal } 109235faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal 109335faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal public void setStatusHints(StatusHints statusHints) { 109435faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal mStatusHints = statusHints; 109535faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal for (Listener l : mListeners) { 109635faf8cf29dc0f4a73935478e0fba957df9619d6Sailesh Nepal l.onStatusHintsChanged(this); 10977e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal } 10987e66957928c5c23a1028c8e2a2d7cf359cbfa44eSailesh Nepal } 10999f2bed31374a56487f370be01224baf6ce97e8adBen Gilad} 1100