1e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon/* 2e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * Copyright (C) 2014 The Android Open Source Project 3e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * 4e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 5e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * you may not use this file except in compliance with the License. 6e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * You may obtain a copy of the License at 7e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * 8e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * http://www.apache.org/licenses/LICENSE-2.0 9e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * 10e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * Unless required by applicable law or agreed to in writing, software 11e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 12e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * See the License for the specific language governing permissions and 14e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * limitations under the License. 15e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon */ 16e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom; 18e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 1961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport android.Manifest; 20e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordonimport android.content.ComponentName; 21e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordonimport android.content.Context; 22e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordonimport android.content.Intent; 23e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordonimport android.content.ServiceConnection; 2461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport android.content.pm.PackageManager; 2561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport android.content.pm.ResolveInfo; 2661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport android.content.pm.ServiceInfo; 27fdfcafaa7913adab35724c9fc7560fbbbb1561aeSantos Cordonimport android.content.res.Resources; 2884fa5f8c59a1cd3c5716c239fb19c58244fc81feSailesh Nepalimport android.net.Uri; 29e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordonimport android.os.IBinder; 30e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordonimport android.os.RemoteException; 3160e7584fe6a1ab878458e4e89f83b77f30416f46Amith Yamasaniimport android.os.UserHandle; 327cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.AudioState; 337cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.CallProperties; 347cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.CallState; 357cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.InCallService; 367cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.ParcelableCall; 377cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.PhoneCapabilities; 387cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.TelecomManager; 3961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport android.util.ArrayMap; 40a439e1b6d6201dedecfc40b67c9347a8c563b9c1Sailesh Nepal 4191d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn// TODO: Needed for move to system service: import com.android.internal.R; 427cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport com.android.internal.telecom.IInCallService; 43810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepalimport com.google.common.collect.ImmutableCollection; 44e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 45a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordonimport java.util.ArrayList; 4661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport java.util.Iterator; 47a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordonimport java.util.List; 4861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport java.util.Map; 4961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunnimport java.util.concurrent.ConcurrentHashMap; 50a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 51e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon/** 52e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * Binds to {@link IInCallService} and provides the service to {@link CallsManager} through which it 53e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * can send updates to the in-call app. This class is created and owned by CallsManager and retains 54e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal * a binding to the {@link IInCallService} (implemented by the in-call app). 55e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon */ 56810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepalpublic final class InCallController extends CallsManagerListenerBase { 57e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon /** 58e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * Used to bind to the in-call app and triggers the start of communication between 59e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal * this class and in-call app. 60e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon */ 61e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon private class InCallServiceConnection implements ServiceConnection { 62e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon /** {@inheritDoc} */ 63e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon @Override public void onServiceConnected(ComponentName name, IBinder service) { 64aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.d(this, "onServiceConnected: %s", name); 6561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn onConnected(name, service); 66e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 67e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 68e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon /** {@inheritDoc} */ 69e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon @Override public void onServiceDisconnected(ComponentName name) { 70aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.d(this, "onDisconnected: %s", name); 7161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn onDisconnected(name); 72e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 73e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 74e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 75e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal private final Call.Listener mCallListener = new Call.ListenerBase() { 76e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 77e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal public void onCallCapabilitiesChanged(Call call) { 78e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal updateCall(call); 79e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 80e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 81e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 82e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal public void onCannedSmsResponsesLoaded(Call call) { 83e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal updateCall(call); 84e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 85e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 86e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 873bcf935b25470e94c8c6855862434d15b785c54aAndrew Lee public void onVideoCallProviderChanged(Call call) { 88e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal updateCall(call); 89e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 90e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 91e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 92e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal public void onStatusHintsChanged(Call call) { 93e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal updateCall(call); 94e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 95e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 96e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 97e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal public void onHandleChanged(Call call) { 98e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal updateCall(call); 99e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 100e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 101e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal @Override 102e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal public void onCallerDisplayNameChanged(Call call) { 103e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal updateCall(call); 104e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal } 1054a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee 1064a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee @Override 1074a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee public void onVideoStateChanged(Call call) { 1084a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee updateCall(call); 1094a79660c984d54679ad4d2bdc89e224d9c8c375bAndrew Lee } 1109d58de5df05d0358fc8ae57ab7e9a0c45337c602Sailesh Nepal 1119d58de5df05d0358fc8ae57ab7e9a0c45337c602Sailesh Nepal @Override 112b78b27693afbe9736f0a54ec473328955251f885Ihab Awad public void onTargetPhoneAccountChanged(Call call) { 11369eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad updateCall(call); 11469eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad } 11512d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon 11612d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon @Override 11712d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon public void onConferenceableCallsChanged(Call call) { 11812d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon updateCall(call); 11912d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon } 120e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal }; 121e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 12261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn /** 12361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * Maintains a binding connection to the in-call app(s). 12461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 12561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * load factor before resizing, 1 means we only expect a single thread to 12661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * access the map so make only a single shard 12761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn */ 12861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn private final Map<ComponentName, InCallServiceConnection> mServiceConnections = 12961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn new ConcurrentHashMap<ComponentName, InCallServiceConnection>(8, 0.9f, 1); 130e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 13161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn /** The in-call app implementations, see {@link IInCallService}. */ 13261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn private final Map<ComponentName, IInCallService> mInCallServices = new ArrayMap<>(); 133e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 134e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal private final CallIdMapper mCallIdMapper = new CallIdMapper("InCall"); 135e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal 13612bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn /** The {@link ComponentName} of the default InCall UI. */ 137d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon private final ComponentName mInCallComponentName; 13861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 13991d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn private final Context mContext; 14091d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn 14191d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn public InCallController(Context context) { 14291d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn mContext = context; 14391d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn Resources resources = mContext.getResources(); 14461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 14561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn mInCallComponentName = new ComponentName( 14661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn resources.getString(R.string.ui_default_package), 14761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn resources.getString(R.string.incall_default_class)); 148e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 149e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 150810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal @Override 151810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal public void onCallAdded(Call call) { 15261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (mInCallServices.isEmpty()) { 153810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal bind(); 154810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal } else { 155aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.i(this, "onCallAdded: %s", call); 15661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn // Track the call if we don't already know about it. 15761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn addCall(call); 15861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 15912bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) { 16012bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn ComponentName componentName = entry.getKey(); 16112bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn IInCallService inCallService = entry.getValue(); 16212bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn 16312bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn ParcelableCall parcelableCall = toParcelableCall(call, 16412bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn componentName.equals(mInCallComponentName) /* includeVideoProvider */); 165ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad try { 16661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn inCallService.addCall(parcelableCall); 167ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } catch (RemoteException ignored) { 168ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 169049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 170049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 171049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 172049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon 173810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal @Override 174810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal public void onCallRemoved(Call call) { 175aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.i(this, "onCallRemoved: %s", call); 176810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal if (CallsManager.getInstance().getCalls().isEmpty()) { 177df39986de36d40aaa45e61d19a21eca536765ca5Santos Cordon // TODO: Wait for all messages to be delivered to the service before unbinding. 178810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal unbind(); 179049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 180e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal call.removeListener(mCallListener); 181e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal mCallIdMapper.removeCall(call); 182049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 183049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon 184810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal @Override 1856fb37c87836b5245046bd3b14320823ab839a10cIhab Awad public void onCallStateChanged(Call call, int oldState, int newState) { 1868c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal updateCall(call); 187cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee } 188cdf3ebd3ea6505668304b7e0a39df354ebbb52fbYorke Lee 1896aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal @Override 190c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal public void onConnectionServiceChanged( 1918c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal Call call, 192c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal ConnectionServiceWrapper oldService, 193c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal ConnectionServiceWrapper newService) { 1948c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal updateCall(call); 1958c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 1968c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal 1978c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal @Override 1986fb37c87836b5245046bd3b14320823ab839a10cIhab Awad public void onAudioStateChanged(AudioState oldAudioState, AudioState newAudioState) { 19961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (!mInCallServices.isEmpty()) { 2006aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal Log.i(this, "Calling onAudioStateChanged, audioState: %s -> %s", oldAudioState, 2016aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal newAudioState); 20261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn for (IInCallService inCallService : mInCallServices.values()) { 20361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn try { 20461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn inCallService.onAudioStateChanged(newAudioState); 20561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } catch (RemoteException ignored) { 20661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 2076aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal } 2086aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal } 2096aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal } 2106aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal 211352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton void onPostDialWait(Call call, String remaining) { 21261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (!mInCallServices.isEmpty()) { 213352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton Log.i(this, "Calling onPostDialWait, remaining = %s", remaining); 21461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn for (IInCallService inCallService : mInCallServices.values()) { 21561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn try { 21661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn inCallService.setPostDialWait(mCallIdMapper.getCallId(call), remaining); 21761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } catch (RemoteException ignored) { 21861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 219352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton } 220352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton } 221352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton } 222352105c5d33ac94e5ad0cb5ac2e9268731423e65Evan Charlton 223a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon @Override 224a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon public void onIsConferencedChanged(Call call) { 2250fbe6321e341ddce186634266dba2db3fa426b88Santos Cordon Log.d(this, "onIsConferencedChanged %s", call); 226a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon updateCall(call); 227a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 228a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 229f3671a6f38a4af68603daf4c2025f572129eada8Santos Cordon void bringToForeground(boolean showDialpad) { 23061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (!mInCallServices.isEmpty()) { 23161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn for (IInCallService inCallService : mInCallServices.values()) { 23261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn try { 23361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn inCallService.bringToForeground(showDialpad); 23461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } catch (RemoteException ignored) { 23561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 236f3671a6f38a4af68603daf4c2025f572129eada8Santos Cordon } 237f3671a6f38a4af68603daf4c2025f572129eada8Santos Cordon } else { 238f3671a6f38a4af68603daf4c2025f572129eada8Santos Cordon Log.w(this, "Asking to bring unbound in-call UI to foreground."); 239f3671a6f38a4af68603daf4c2025f572129eada8Santos Cordon } 240f3671a6f38a4af68603daf4c2025f572129eada8Santos Cordon } 241f3671a6f38a4af68603daf4c2025f572129eada8Santos Cordon 242049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon /** 243049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon * Unbinds an existing bound connection to the in-call app. 244049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon */ 245810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal private void unbind() { 246049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon ThreadUtil.checkOnMainThread(); 247d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon Iterator<Map.Entry<ComponentName, InCallServiceConnection>> iterator = 248d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon mServiceConnections.entrySet().iterator(); 249d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon while (iterator.hasNext()) { 250d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon Log.i(this, "Unbinding from InCallService %s"); 25191d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn mContext.unbindService(iterator.next().getValue()); 252d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon iterator.remove(); 253049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 254d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon mInCallServices.clear(); 255049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 256049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon 257049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon /** 258e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * Binds to the in-call app if not already connected by binding directly to the saved 259e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * component name of the {@link IInCallService} implementation. 260e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon */ 261049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon private void bind() { 262e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon ThreadUtil.checkOnMainThread(); 26361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (mInCallServices.isEmpty()) { 26491d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn PackageManager packageManager = mContext.getPackageManager(); 265d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE); 26661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 267d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon for (ResolveInfo entry : packageManager.queryIntentServices(serviceIntent, 0)) { 26861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn ServiceInfo serviceInfo = entry.serviceInfo; 26961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (serviceInfo != null) { 27061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn boolean hasServiceBindPermission = serviceInfo.permission != null && 27161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn serviceInfo.permission.equals( 27261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn Manifest.permission.BIND_INCALL_SERVICE); 27361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn boolean hasControlInCallPermission = packageManager.checkPermission( 27461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn Manifest.permission.CONTROL_INCALL_EXPERIENCE, 27561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED; 27661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 27761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (!hasServiceBindPermission) { 27861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn Log.w(this, "InCallService does not have BIND_INCALL_SERVICE permission: " + 27961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn serviceInfo.packageName); 28061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn continue; 28161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 28261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 28361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (!hasControlInCallPermission) { 28461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn Log.w(this, 28561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn "InCall UI does not have CONTROL_INCALL_EXPERIENCE permission: " + 28661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn serviceInfo.packageName); 28761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn continue; 28861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 28961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 29061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn InCallServiceConnection inCallServiceConnection = new InCallServiceConnection(); 29161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn ComponentName componentName = new ComponentName(serviceInfo.packageName, 29261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn serviceInfo.name); 29361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 2944f50f8e29d7479351ec344ec592686708ff01055Santos Cordon Log.i(this, "Attempting to bind to InCall %s, is dupe? %b ", 2954f50f8e29d7479351ec344ec592686708ff01055Santos Cordon serviceInfo.packageName, 2964f50f8e29d7479351ec344ec592686708ff01055Santos Cordon mServiceConnections.containsKey(componentName)); 2974f50f8e29d7479351ec344ec592686708ff01055Santos Cordon 298d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon if (!mServiceConnections.containsKey(componentName)) { 299d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon Intent intent = new Intent(InCallService.SERVICE_INTERFACE); 300d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon intent.setComponent(componentName); 301d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon 30291d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn if (mContext.bindServiceAsUser(intent, inCallServiceConnection, 303d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) { 304d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon mServiceConnections.put(componentName, inCallServiceConnection); 305d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon } 30661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 30761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 308e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 309e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 310e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 311e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 312e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon /** 313e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * Persists the {@link IInCallService} instance and starts the communication between 314e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal * this class and in-call app by sending the first update to in-call app. This method is 315e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * called after a successful binding connection is established. 316e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * 31761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * @param componentName The service {@link ComponentName}. 318e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon * @param service The {@link IInCallService} implementation. 319e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon */ 32061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn private void onConnected(ComponentName componentName, IBinder service) { 321e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon ThreadUtil.checkOnMainThread(); 32261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 323aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.i(this, "onConnected to %s", componentName); 324aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee 32561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn IInCallService inCallService = IInCallService.Stub.asInterface(service); 326e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 327e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon try { 32861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn inCallService.setInCallAdapter(new InCallAdapter(CallsManager.getInstance(), 329e59bb195972d65a71618af4fe13f1ad982253e16Sailesh Nepal mCallIdMapper)); 33061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn mInCallServices.put(componentName, inCallService); 331e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } catch (RemoteException e) { 332f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal Log.e(this, e, "Failed to set the in-call adapter."); 333810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal return; 334e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 335e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 33661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn // Upon successful connection, send the state of the world to the service. 337810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal ImmutableCollection<Call> calls = CallsManager.getInstance().getCalls(); 338810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal if (!calls.isEmpty()) { 339aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(), 340aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee componentName); 341810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal for (Call call : calls) { 34261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn try { 34361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn // Track the call if we don't already know about it. 344aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.i(this, "addCall after binding: %s", call); 34561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn addCall(call); 34661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 34712bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn inCallService.addCall(toParcelableCall(call, 34812bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn componentName.equals(mInCallComponentName) /* includeVideoProvider */)); 34961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } catch (RemoteException ignored) { 35061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 351810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal } 3526aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal onAudioStateChanged(null, CallsManager.getInstance().getAudioState()); 353810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal } else { 354810735e3f0a4fe924a805981d32b6916ec834b38Sailesh Nepal unbind(); 355049b7b6a8d0cf44d687d827cb57a18fa23358206Santos Cordon } 356e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 357e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon 358e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon /** 35961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * Cleans up an instance of in-call app after the service has been unbound. 36061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * 36161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * @param disconnectedComponent The {@link ComponentName} of the service which disconnected. 362e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon */ 36361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn private void onDisconnected(ComponentName disconnectedComponent) { 364aaa88dd2d46639092b95b290ac28ac81e8319dd3Yorke Lee Log.i(this, "onDisconnected from %s", disconnectedComponent); 365e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon ThreadUtil.checkOnMainThread(); 366d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon 36761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (mInCallServices.containsKey(disconnectedComponent)) { 36861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn mInCallServices.remove(disconnectedComponent); 36961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 37061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 371d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon if (mServiceConnections.containsKey(disconnectedComponent)) { 372d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon // One of the services that we were bound to has disconnected. If the default in-call UI 373d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon // has disconnected, disconnect all calls and un-bind all other InCallService 374d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon // implementations. 375d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon if (disconnectedComponent.equals(mInCallComponentName)) { 376d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon Log.i(this, "In-call UI %s disconnected.", disconnectedComponent); 377d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon CallsManager.getInstance().disconnectAllCalls(); 378d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon unbind(); 379d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon } else { 380d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon Log.i(this, "In-Call Service %s suddenly disconnected", disconnectedComponent); 381d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon // Else, if it wasn't the default in-call UI, then one of the other in-call services 382d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon // disconnected and, well, that's probably their fault. Clear their state and 383d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon // ignore. 384d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon InCallServiceConnection serviceConnection = 385d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon mServiceConnections.get(disconnectedComponent); 386d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon 387d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon // We still need to call unbind even though it disconnected. 38891d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn mContext.unbindService(serviceConnection); 389d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon 390d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon mServiceConnections.remove(disconnectedComponent); 391d93a441281e2505cc305b8037847feb1a27f9c08Santos Cordon mInCallServices.remove(disconnectedComponent); 39261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 39361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 394e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon } 3958c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal 39612bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn /** 39712bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * Informs all {@link InCallService} instances of the updated call information. Changes to the 39812bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * video provider are only communicated to the default in-call UI. 39912bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * 40012bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * @param call The {@link Call}. 40112bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn */ 4028c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal private void updateCall(Call call) { 40361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (!mInCallServices.isEmpty()) { 40412bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) { 40512bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn ComponentName componentName = entry.getKey(); 40612bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn IInCallService inCallService = entry.getValue(); 40712bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn ParcelableCall parcelableCall = toParcelableCall(call, 40812bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn componentName.equals(mInCallComponentName) /* includeVideoProvider */); 40912bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn 41012bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn Log.v(this, "updateCall %s ==> %s", call, parcelableCall); 41161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn try { 41261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn inCallService.updateCall(parcelableCall); 41361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } catch (RemoteException ignored) { 41461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 4158c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 4168c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 4178c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 4188c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal 41912bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn /** 42012bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance. 42112bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * 42212bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * @param call The {@link Call} to parcel. 42312bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * @param includeVideoProvider When {@code true}, the {@link IVideoProvider} is included in the 42412bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * parcelled call. When {@code false}, the {@link IVideoProvider} is not included. 42512bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn * @return The {@link ParcelableCall} containing all call information from the {@link Call}. 42612bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn */ 42712bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn private ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider) { 4288c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal String callId = mCallIdMapper.getCallId(call); 4298c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal 430e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal int capabilities = call.getCallCapabilities(); 4314b034a6b5901291fe06db397d394c484e68d7781Santos Cordon if (CallsManager.getInstance().isAddCallCapable(call)) { 4326fb37c87836b5245046bd3b14320823ab839a10cIhab Awad capabilities |= PhoneCapabilities.ADD_CALL; 43310838c23aa209b364812cf1dcc23a3793234fb0dSantos Cordon } 4341711aec69264a36fda29c825bc6fb8fbceeb1efdTyler Gunn 43510ce856c075a06e7300dfc279a88279b0716d43cYorke Lee // Disable mute and add call for emergency calls. 4361711aec69264a36fda29c825bc6fb8fbceeb1efdTyler Gunn if (call.isEmergencyCall()) { 4371711aec69264a36fda29c825bc6fb8fbceeb1efdTyler Gunn capabilities &= ~PhoneCapabilities.MUTE; 43810ce856c075a06e7300dfc279a88279b0716d43cYorke Lee capabilities &= ~PhoneCapabilities.ADD_CALL; 439a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 440e20bc974ffc24d852d09e153a280b51e0329299cSailesh Nepal 441bfffd2d175cc0219e512f64ff47d1e9ba5a50affAndrew Lee int properties = call.isConference() ? CallProperties.CONFERENCE : 0; 442bfffd2d175cc0219e512f64ff47d1e9ba5a50affAndrew Lee 4436fb37c87836b5245046bd3b14320823ab839a10cIhab Awad int state = call.getState(); 4448c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal if (state == CallState.ABORTED) { 4458c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal state = CallState.DISCONNECTED; 4465dfd3800f15e9b0f1420813d8d7638e1cf9d621dSantos Cordon } 4475dfd3800f15e9b0f1420813d8d7638e1cf9d621dSantos Cordon 4485dfd3800f15e9b0f1420813d8d7638e1cf9d621dSantos Cordon if (call.isLocallyDisconnecting() && state != CallState.DISCONNECTED) { 449aa47937652d80d8bd19860ec521d28ffea745e63Tyler Gunn state = CallState.DISCONNECTING; 4508c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 451a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 452a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon String parentCallId = null; 453a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon Call parentCall = call.getParentCall(); 454a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (parentCall != null) { 455a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon parentCallId = mCallIdMapper.getCallId(parentCall); 456a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 457a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 458a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon long connectTimeMillis = call.getConnectTimeMillis(); 459a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon List<Call> childCalls = call.getChildCalls(); 460a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon List<String> childCallIds = new ArrayList<>(); 461a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon if (!childCalls.isEmpty()) { 462a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon connectTimeMillis = Long.MAX_VALUE; 463a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon for (Call child : childCalls) { 464a9173085c5c176d3f632e50e962701bba2473b2aYorke Lee if (child.getConnectTimeMillis() > 0) { 465a9173085c5c176d3f632e50e962701bba2473b2aYorke Lee connectTimeMillis = Math.min(child.getConnectTimeMillis(), connectTimeMillis); 466a9173085c5c176d3f632e50e962701bba2473b2aYorke Lee } 467a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon childCallIds.add(mCallIdMapper.getCallId(child)); 468a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 469a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon } 470a161070ea054f91a5b2d5b4e3413381134d548b8Santos Cordon 471ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad if (call.isRespondViaSmsCapable()) { 4726fb37c87836b5245046bd3b14320823ab839a10cIhab Awad capabilities |= PhoneCapabilities.RESPOND_VIA_TEXT; 473ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad } 474ff7493a8f620509d41dd8a5106c1d0dcd27cd274Ihab Awad 4757cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunn Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ? 476e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal call.getHandle() : null; 477e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal String callerDisplayName = call.getCallerDisplayNamePresentation() == 4787cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunn TelecomManager.PRESENTATION_ALLOWED ? call.getCallerDisplayName() : null; 479e8ecb98d5341395e073d02c065143ae3ac76ef71Sailesh Nepal 48012d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon List<Call> conferenceableCalls = call.getConferenceableCalls(); 48112d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size()); 48212d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon for (Call otherCall : conferenceableCalls) { 48312d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon String otherId = mCallIdMapper.getCallId(otherCall); 48412d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon if (otherId != null) { 48512d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon conferenceableCallIds.add(otherId); 48612d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon } 48712d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon } 48812d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon 4892583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon return new ParcelableCall( 4902583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon callId, 4912583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon state, 4922583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon call.getDisconnectCause(), 4932583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon call.getCannedSmsResponses(), 4942583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon capabilities, 495bfffd2d175cc0219e512f64ff47d1e9ba5a50affAndrew Lee properties, 4962583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon connectTimeMillis, 4972583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon handle, 4982583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon call.getHandlePresentation(), 4992583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon callerDisplayName, 5002583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon call.getCallerDisplayNamePresentation(), 5012583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon call.getGatewayInfo(), 502b78b27693afbe9736f0a54ec473328955251f885Ihab Awad call.getTargetPhoneAccount(), 50312bccade85d58ca73d861aeba26ee25e97681895Tyler Gunn includeVideoProvider ? call.getVideoProvider() : null, 5042583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon parentCallId, 5052583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon childCallIds, 5062583b67c376358538cfa11e25a241adb2dc9e34aSantos Cordon call.getStatusHints(), 50712d61825cd0d6aa06272db3f77b5e30dce379951Santos Cordon call.getVideoState(), 508a9d91da9fcf2d8223ec6e0ffb9bd2d506c5a25feNancy Chen conferenceableCallIds, 509a9d91da9fcf2d8223ec6e0ffb9bd2d506c5a25feNancy Chen call.getExtras()); 5108c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal } 51161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn 51261b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn /** 51361b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * Adds the call to the list of calls tracked by the {@link InCallController}. 51461b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn * @param call The call to add. 51561b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn */ 51661b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn private void addCall(Call call) { 51761b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn if (mCallIdMapper.getCallId(call) == null) { 51861b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn mCallIdMapper.addCall(call); 51961b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn call.addListener(mCallListener); 52061b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 52161b9210e5757db0cb49424fe917be0f788ea2218Tyler Gunn } 522e3d76abbb6c7c726980abed522f6c3efcbb6019eSantos Cordon} 523