CallList.java revision 8b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0c
196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon/* 296b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * Copyright (C) 2013 The Android Open Source Project 396b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * 496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 596b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * you may not use this file except in compliance with the License. 696b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * You may obtain a copy of the License at 796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * 896b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * http://www.apache.org/licenses/LICENSE-2.0 996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * 1096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * Unless required by applicable law or agreed to in writing, software 1196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 1296b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * See the License for the specific language governing permissions and 1496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon * limitations under the License 1596b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon */ 1696b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 1796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonpackage com.android.incallui; 1896b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 198b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Chengimport com.google.android.collect.Lists; 2096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonimport com.google.android.collect.Maps; 21a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordonimport com.google.android.collect.Sets; 2296b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonimport com.google.common.base.Preconditions; 23671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon 24a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordonimport android.os.Handler; 25a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordonimport android.os.Message; 26a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 2796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonimport com.android.services.telephony.common.Call; 2896b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 2910196fd2f7cc922693e2a7c6c932725a52157943Christine Chenimport java.util.ArrayList; 3096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonimport java.util.HashMap; 3196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonimport java.util.List; 32a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordonimport java.util.Set; 3396b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 3496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon/** 35671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon * Maintains the list of active calls received from CallHandlerService and notifies interested 36671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon * classes of changes to the call list as they are received from the telephony stack. 37671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon * Primary lister of changes to this class is InCallPresenter. 3896b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon */ 3996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonpublic class CallList { 40671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon 41930ea81045240d6b690663f94c4c86ea045229d1Santos Cordon private static final int DISCONNECTED_CALL_TIMEOUT_MS = 2000; 42a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 43a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon private static final int EVENT_DISCONNECTED_TIMEOUT = 1; 44a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 458b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng private static CallList sInstance = new CallList(); 46a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 47a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon private final HashMap<Integer, Call> mCallMap = Maps.newHashMap(); 4810196fd2f7cc922693e2a7c6c932725a52157943Christine Chen private final HashMap<Integer, ArrayList<String>> mCallTextReponsesMap = 4910196fd2f7cc922693e2a7c6c932725a52157943Christine Chen Maps.newHashMap(); 50a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon private final Set<Listener> mListeners = Sets.newArraySet(); 518b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng private final HashMap<Integer, List<CallUpdateListener>> mCallUpdateListenerMap = Maps 528b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng .newHashMap(); 538b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 54a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 55a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon /** 56a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * Static singleton accessor method. 57a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon */ 588b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public static CallList getInstance() { 59a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon return sInstance; 608b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 6196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 62a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon /** 63a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * Private constructor. Instance should only be acquired through getInstance(). 64a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon */ 658b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng private CallList() { 66a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 6796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 68a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon /** 69a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * Called when a single call has changed. 70a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon */ 7196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon public void onUpdate(Call call) { 721a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(this, "onUpdate - ", call); 73a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 74a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon updateCallInMap(call); 75a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon notifyListenersOfChange(); 76a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon } 77a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 78a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon /** 79a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon * Called when a single call disconnects. 80a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon */ 81a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon public void onDisconnect(Call call) { 821a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(this, "onDisconnect: ", call); 83a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 84671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon updateCallInMap(call); 8510196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 8610196fd2f7cc922693e2a7c6c932725a52157943Christine Chen notifyListenersOfChange(); 8710196fd2f7cc922693e2a7c6c932725a52157943Christine Chen } 8810196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 8910196fd2f7cc922693e2a7c6c932725a52157943Christine Chen /** 9010196fd2f7cc922693e2a7c6c932725a52157943Christine Chen * Called when a single call has changed. 9110196fd2f7cc922693e2a7c6c932725a52157943Christine Chen */ 928b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public void onIncoming(Call call, List<String> textMessages) { 938b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng Log.d(this, "onIncoming - " + call); 9410196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 958b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng updateCallInMap(call); 968b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng updateCallTextMap(call, textMessages); 9710196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 988b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng for (Listener listener : mListeners) { 998b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng listener.onIncomingCall(call); 1008b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 10196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon } 10296b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 103a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon /** 104a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * Called when multiple calls have changed. 105a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon */ 10696b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon public void onUpdate(List<Call> callsToUpdate) { 1071a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(this, "onUpdate(...)"); 108671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon 10996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon Preconditions.checkNotNull(callsToUpdate); 11096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon for (Call call : callsToUpdate) { 1111a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(this, "\t" + call); 112671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon 11396b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon updateCallInMap(call); 11410196fd2f7cc922693e2a7c6c932725a52157943Christine Chen updateCallTextMap(call, null); 1158b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 1168b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng notifyCallUpdateListeners(call); 11796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon } 118a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 119a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon notifyListenersOfChange(); 120a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 121a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 1228b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public void notifyCallUpdateListeners(Call call) { 1238b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getCallId()); 1248b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng if (listeners != null) { 1258b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng for (CallUpdateListener listener : listeners) { 1268b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng listener.onCallStateChanged(call); 1278b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 1288b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 1298b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 1308b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 1318b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng /** 1328b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * Add a call update listener for a call id. 1338b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * 1348b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * @param callId The call id to get updates for. 1358b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * @param listener The listener to add. 1368b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng */ 1378b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public void addCallUpdateListener(int callId, CallUpdateListener listener) { 1388b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(callId); 1398b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng if (listeners == null) { 1408b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng listeners = Lists.newArrayList(); 1418b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng mCallUpdateListenerMap.put(callId, listeners); 1428b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 1438b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng listeners.add(listener); 1448b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 1458b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 1468b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng /** 1478b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * Remove a call update listener for a call id. 1488b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * 1498b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * @param callId The call id to remove the listener for. 1508b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng * @param listener The listener to remove. 1518b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng */ 1528b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public void removeCallUpdateListener(int callId, CallUpdateListener listener) { 1538b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(callId); 1548b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng if (listeners != null) { 1558b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng listeners.remove(listener); 1568b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 1578b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 1588b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 159a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon public void addListener(Listener listener) { 160a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon Preconditions.checkNotNull(listener); 161150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon 162a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon mListeners.add(listener); 163150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon 164150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon // Let the listener know about the active calls immediately. 165150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon listener.onCallListChange(this); 166a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 167a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 168a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon public void removeListener(Listener listener) { 169a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon Preconditions.checkNotNull(listener); 170a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon mListeners.remove(listener); 171a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 172a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 173a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon /** 174e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon * TODO: Change so that this function is not needed. Instead of assuming there is an active 175a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * call, the code should rely on the status of a specific Call and allow the presenters to 176a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * update the Call object when the active call changes. 177a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon */ 178a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon public Call getIncomingOrActive() { 179150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon Call retval = getIncomingCall(); 180150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon if (retval == null) { 181671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon retval = getActiveCall(); 182150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon } 183150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon return retval; 184150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon } 185150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon 186e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon public Call getOutgoingCall() { 187e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon return getFirstCallWithState(Call.State.DIALING); 188e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon } 189e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon 190671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon public Call getActiveCall() { 191671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon return getFirstCallWithState(Call.State.ACTIVE); 192671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon } 193671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon 194150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon public Call getBackgroundCall() { 195150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon return getFirstCallWithState(Call.State.ONHOLD); 196150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon } 197150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon 198a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon public Call getDisconnectedCall() { 199a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon return getFirstCallWithState(Call.State.DISCONNECTED); 200a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon } 201a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 202efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon public Call getSecondBackgroundCall() { 203efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon return getCallWithState(Call.State.ONHOLD, 1); 204efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon } 205efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon 206efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon public Call getActiveOrBackgroundCall() { 207efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon Call call = getActiveCall(); 208efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon if (call == null) { 209efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon call = getBackgroundCall(); 210efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon } 211efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon return call; 212efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon } 213efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon 214150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon public Call getIncomingCall() { 215efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon Call call = getFirstCallWithState(Call.State.INCOMING); 216efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon if (call == null) { 217efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon call = getFirstCallWithState(Call.State.CALL_WAITING); 218efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon } 219efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon 220efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon return call; 221150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon } 222a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 2238b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 2248b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public Call getFirstCall() { 2258b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng // TODO: should we switch to a simple list and pull the first one? 2268b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng Call result = getIncomingCall(); 2278b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng if (result == null) { 2288b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng result = getFirstCallWithState(Call.State.DIALING); 2298b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 2308b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng if (result == null) { 2318b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng result = getFirstCallWithState(Call.State.ACTIVE); 2328b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 2338b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng return result; 2348b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 2358b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 236150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon public boolean existsLiveCall() { 237a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon for (Call call : mCallMap.values()) { 238150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon if (!isCallDead(call)) { 239150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon return true; 240150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon } 241150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon } 242150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon return false; 243150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon } 244150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon 2458b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public ArrayList<String> getTextResponses(int callId) { 2468b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng return mCallTextReponsesMap.get(callId); 24710196fd2f7cc922693e2a7c6c932725a52157943Christine Chen } 24810196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 249150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon /** 250150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon * Returns first call found in the call map with the specified state. 251150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon */ 252150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon public Call getFirstCallWithState(int state) { 253efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon return getCallWithState(state, 0); 254efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon } 255efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon 256efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon /** 257efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon * Returns the [position]th call found in the call map with the specified state. 258efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon * TODO(klp): Improve this logic to sort by call time. 259efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon */ 260efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon public Call getCallWithState(int state, int positionToFind) { 261150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon Call retval = null; 262efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon int position = 0; 263150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon for (Call call : mCallMap.values()) { 264150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon if (call.getState() == state) { 265efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon if (position >= positionToFind) { 266efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon retval = call; 267efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon break; 268efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon } else { 269efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon position++; 270efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon } 271a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 272a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 273a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 274a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon return retval; 275a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 276a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 277a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon /** 2783c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon * This is called when the service disconnects, either expectedly or unexpectedly. 2793c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon * For the expected case, it's because we have no calls left. For the unexpected case, 2803c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon * it is likely a crash of phone and we need to clean up our calls manually. Without phone, 2813c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon * there can be no active calls, so this is relatively safe thing to do. 2823c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon */ 2833c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon public void clearOnDisconnect() { 2843c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon for (Call call : mCallMap.values()) { 2853c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon final int state = call.getState(); 2863c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon if (state != Call.State.IDLE && 2873c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon state != Call.State.INVALID && 2883c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon state != Call.State.DISCONNECTED) { 2893c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon call.setState(Call.State.DISCONNECTED); 2903c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon updateCallInMap(call); 2913c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon } 2923c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon } 2933c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon notifyListenersOfChange(); 2943c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon } 2953c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon 2963c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon /** 297a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * Sends a generic notification to all listeners that something has changed. 298a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * It is up to the listeners to call back to determine what changed. 299a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon */ 300a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon private void notifyListenersOfChange() { 301a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon for (Listener listener : mListeners) { 302a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon listener.onCallListChange(this); 303a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 30496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon } 30596b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 30696b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon private void updateCallInMap(Call call) { 30796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon Preconditions.checkNotNull(call); 30896b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 30996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon final Integer id = new Integer(call.getCallId()); 31096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 311a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon if (call.getState() == Call.State.DISCONNECTED) { 312a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 3131df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon // update existing (but do not add!!) disconnected calls 3141df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon if (mCallMap.containsKey(id)) { 315a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 3161df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon // For disconnected calls, we want to keep them alive for a few seconds so that the 3171df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon // UI has a chance to display anything it needs when a call is disconnected. 3181df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon 3191df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon // Set up a timer to destroy the call after X seconds. 3201df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon final Message msg = mHandler.obtainMessage(EVENT_DISCONNECTED_TIMEOUT, call); 3211df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon mHandler.sendMessageDelayed(msg, DISCONNECTED_CALL_TIMEOUT_MS); 322a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 323a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon mCallMap.put(id, call); 324a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon } 325a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon } else if (!isCallDead(call)) { 326a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon mCallMap.put(id, call); 327a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } else if (mCallMap.containsKey(id)) { 328a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon mCallMap.remove(id); 32996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon } 33096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon } 33196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon 33210196fd2f7cc922693e2a7c6c932725a52157943Christine Chen private void updateCallTextMap(Call call, List<String> textResponses) { 33310196fd2f7cc922693e2a7c6c932725a52157943Christine Chen Preconditions.checkNotNull(call); 33410196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 33510196fd2f7cc922693e2a7c6c932725a52157943Christine Chen final Integer id = new Integer(call.getCallId()); 33610196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 33710196fd2f7cc922693e2a7c6c932725a52157943Christine Chen if (!isCallDead(call)) { 33810196fd2f7cc922693e2a7c6c932725a52157943Christine Chen if (textResponses != null) { 33910196fd2f7cc922693e2a7c6c932725a52157943Christine Chen mCallTextReponsesMap.put(id, (ArrayList<String>) textResponses); 34010196fd2f7cc922693e2a7c6c932725a52157943Christine Chen } 34110196fd2f7cc922693e2a7c6c932725a52157943Christine Chen } else if (mCallMap.containsKey(id)) { 34210196fd2f7cc922693e2a7c6c932725a52157943Christine Chen mCallTextReponsesMap.remove(id); 34310196fd2f7cc922693e2a7c6c932725a52157943Christine Chen } 34410196fd2f7cc922693e2a7c6c932725a52157943Christine Chen } 34510196fd2f7cc922693e2a7c6c932725a52157943Christine Chen 346a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon private boolean isCallDead(Call call) { 34796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon final int state = call.getState(); 348a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon return Call.State.IDLE == state || Call.State.INVALID == state; 349a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon } 350a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon 351671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon /** 352a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon * Sets up a call for deletion and notifies listeners of change. 353a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon */ 354a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon private void finishDisconnectedCall(Call call) { 355a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon call.setState(Call.State.IDLE); 356a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon updateCallInMap(call); 357a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon notifyListenersOfChange(); 358a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon } 359a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 360a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon /** 361a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon * Handles the timeout for destroying disconnected calls. 362a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon */ 363a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon private Handler mHandler = new Handler() { 364a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon @Override 365a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon public void handleMessage(Message msg) { 366a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon switch (msg.what) { 367a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon case EVENT_DISCONNECTED_TIMEOUT: 3681a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.d(this, "EVENT_DISCONNECTED_TIMEOUT ", msg.obj); 369a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon finishDisconnectedCall((Call) msg.obj); 370a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon break; 371a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon default: 3721a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng Log.wtf(this, "Message not expected: " + msg.what); 373a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon break; 374a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon } 375a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon } 376a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon }; 377a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon 378a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon /** 379a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * Listener interface for any class that wants to be notified of changes 380a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon * to the call list. 381a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon */ 382a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon public interface Listener { 383a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon public void onCallListChange(CallList callList); 3848b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public void onIncomingCall(Call call); 3858b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng } 3868b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng 3878b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public interface CallUpdateListener { 3888b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng // TODO: refactor and limit arg to be call state. Caller info is not needed. 3898b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng public void onCallStateChanged(Call call); 39096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon } 39196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon} 392