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;
28d7effd30eca546cabb5f1d70858b4038fa4a31c3Santos Cordonimport com.android.services.telephony.common.Call.DisconnectCause;
2996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
3010196fd2f7cc922693e2a7c6c932725a52157943Christine Chenimport java.util.ArrayList;
3196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonimport java.util.HashMap;
3296b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonimport java.util.List;
33a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordonimport java.util.Set;
3496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
3596b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon/**
36671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon * Maintains the list of active calls received from CallHandlerService and notifies interested
37671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon * classes of changes to the call list as they are received from the telephony stack.
38671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon * Primary lister of changes to this class is InCallPresenter.
3996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon */
4096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordonpublic class CallList {
41671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon
42ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon    private static final int DISCONNECTED_CALL_SHORT_TIMEOUT_MS = 200;
43ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon    private static final int DISCONNECTED_CALL_MEDIUM_TIMEOUT_MS = 2000;
44ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon    private static final int DISCONNECTED_CALL_LONG_TIMEOUT_MS = 5000;
45a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
46a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    private static final int EVENT_DISCONNECTED_TIMEOUT = 1;
47a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
488b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    private static CallList sInstance = new CallList();
49a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
50a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    private final HashMap<Integer, Call> mCallMap = Maps.newHashMap();
5110196fd2f7cc922693e2a7c6c932725a52157943Christine Chen    private final HashMap<Integer, ArrayList<String>> mCallTextReponsesMap =
5210196fd2f7cc922693e2a7c6c932725a52157943Christine Chen            Maps.newHashMap();
53a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    private final Set<Listener> mListeners = Sets.newArraySet();
548b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    private final HashMap<Integer, List<CallUpdateListener>> mCallUpdateListenerMap = Maps
558b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            .newHashMap();
568b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
57a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
58a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    /**
59a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * Static singleton accessor method.
60a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     */
618b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public static CallList getInstance() {
62a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        return sInstance;
638b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    }
6496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
65a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    /**
66a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * Private constructor.  Instance should only be acquired through getInstance().
67a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     */
688b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    private CallList() {
69a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    }
7096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
71a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    /**
72a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * Called when a single call has changed.
73a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     */
7496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon    public void onUpdate(Call call) {
751a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "onUpdate - ", call);
76a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
77a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        updateCallInMap(call);
78a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        notifyListenersOfChange();
79a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    }
80a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
81a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    /**
82a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon     * Called when a single call disconnects.
83a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon     */
84a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    public void onDisconnect(Call call) {
851a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "onDisconnect: ", call);
86a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
877fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        boolean updated = updateCallInMap(call);
8810196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
897fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        if (updated) {
907fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            // notify those listening for changes on this specific change
917fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            notifyCallUpdateListeners(call);
927fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon
937fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            // notify those listening for all disconnects
947fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            notifyListenersOfDisconnect(call);
957fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        }
9610196fd2f7cc922693e2a7c6c932725a52157943Christine Chen    }
9710196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
9810196fd2f7cc922693e2a7c6c932725a52157943Christine Chen    /**
9910196fd2f7cc922693e2a7c6c932725a52157943Christine Chen     * Called when a single call has changed.
10010196fd2f7cc922693e2a7c6c932725a52157943Christine Chen     */
1018b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public void onIncoming(Call call, List<String> textMessages) {
1028b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        Log.d(this, "onIncoming - " + call);
10310196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
1048b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        updateCallInMap(call);
1058b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        updateCallTextMap(call, textMessages);
10610196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
1078b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        for (Listener listener : mListeners) {
1088b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            listener.onIncomingCall(call);
1098b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
11096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon    }
11196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
112a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    /**
113a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * Called when multiple calls have changed.
114a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     */
11596b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon    public void onUpdate(List<Call> callsToUpdate) {
1161a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "onUpdate(...)");
117671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon
11896b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon        Preconditions.checkNotNull(callsToUpdate);
11996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon        for (Call call : callsToUpdate) {
1201a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.d(this, "\t" + call);
121671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon
12296b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon            updateCallInMap(call);
12310196fd2f7cc922693e2a7c6c932725a52157943Christine Chen            updateCallTextMap(call, null);
1248b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
1258b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            notifyCallUpdateListeners(call);
12696b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon        }
127a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
128a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        notifyListenersOfChange();
129a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    }
130a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
1318b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public void notifyCallUpdateListeners(Call call) {
1328b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getCallId());
1338b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        if (listeners != null) {
1348b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            for (CallUpdateListener listener : listeners) {
1358b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng                listener.onCallStateChanged(call);
1368b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            }
1378b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
1388b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    }
1398b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
1408b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    /**
1418b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     * Add a call update listener for a call id.
1428b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     *
1438b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     * @param callId The call id to get updates for.
1448b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     * @param listener The listener to add.
1458b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     */
1468b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public void addCallUpdateListener(int callId, CallUpdateListener listener) {
1478b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(callId);
1488b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        if (listeners == null) {
1498b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            listeners = Lists.newArrayList();
1508b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            mCallUpdateListenerMap.put(callId, listeners);
1518b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
1528b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        listeners.add(listener);
1538b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    }
1548b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
1558b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    /**
1568b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     * Remove a call update listener for a call id.
1578b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     *
1588b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     * @param callId The call id to remove the listener for.
1598b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     * @param listener The listener to remove.
1608b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng     */
1618b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public void removeCallUpdateListener(int callId, CallUpdateListener listener) {
1628b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(callId);
1638b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        if (listeners != null) {
1648b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            listeners.remove(listener);
1658b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
1668b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    }
1678b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
168a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    public void addListener(Listener listener) {
169a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        Preconditions.checkNotNull(listener);
170150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon
171a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        mListeners.add(listener);
172150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon
173150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        // Let the listener know about the active calls immediately.
174150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        listener.onCallListChange(this);
175a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    }
176a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
177a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    public void removeListener(Listener listener) {
178a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        Preconditions.checkNotNull(listener);
179a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        mListeners.remove(listener);
180a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    }
181a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
182a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    /**
183e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon     * TODO: Change so that this function is not needed. Instead of assuming there is an active
184a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * call, the code should rely on the status of a specific Call and allow the presenters to
185a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * update the Call object when the active call changes.
186a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     */
187a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    public Call getIncomingOrActive() {
188150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        Call retval = getIncomingCall();
189150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        if (retval == null) {
190671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon            retval = getActiveCall();
191150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        }
192150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        return retval;
193150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    }
194150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon
195e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon    public Call getOutgoingCall() {
196672b16d0620d033e10fab30ccd70f5dd23e823b7Santos Cordon        Call call = getFirstCallWithState(Call.State.DIALING);
197672b16d0620d033e10fab30ccd70f5dd23e823b7Santos Cordon        if (call == null) {
198672b16d0620d033e10fab30ccd70f5dd23e823b7Santos Cordon            call = getFirstCallWithState(Call.State.REDIALING);
199672b16d0620d033e10fab30ccd70f5dd23e823b7Santos Cordon        }
200672b16d0620d033e10fab30ccd70f5dd23e823b7Santos Cordon        return call;
201e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon    }
202e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon
203671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon    public Call getActiveCall() {
204671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon        return getFirstCallWithState(Call.State.ACTIVE);
205671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon    }
206671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon
207150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    public Call getBackgroundCall() {
208150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        return getFirstCallWithState(Call.State.ONHOLD);
209150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    }
210150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon
211a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    public Call getDisconnectedCall() {
212a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        return getFirstCallWithState(Call.State.DISCONNECTED);
213a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    }
214a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
215ecabb6923e6587e0f0ca98cc895be7d99e694015Christine Chen    public Call getDisconnectingCall() {
216ecabb6923e6587e0f0ca98cc895be7d99e694015Christine Chen        return getFirstCallWithState(Call.State.DISCONNECTING);
217ecabb6923e6587e0f0ca98cc895be7d99e694015Christine Chen    }
218ecabb6923e6587e0f0ca98cc895be7d99e694015Christine Chen
219efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon    public Call getSecondBackgroundCall() {
220efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        return getCallWithState(Call.State.ONHOLD, 1);
221efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon    }
222efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon
223efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon    public Call getActiveOrBackgroundCall() {
224efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        Call call = getActiveCall();
225efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        if (call == null) {
226efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon            call = getBackgroundCall();
227efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        }
228efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        return call;
229efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon    }
230efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon
231150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    public Call getIncomingCall() {
232efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        Call call = getFirstCallWithState(Call.State.INCOMING);
233efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        if (call == null) {
234efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon            call = getFirstCallWithState(Call.State.CALL_WAITING);
235efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        }
236efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon
237efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        return call;
238150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    }
239a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
2408b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public Call getFirstCall() {
2418b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        Call result = getIncomingCall();
2428b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        if (result == null) {
243672b16d0620d033e10fab30ccd70f5dd23e823b7Santos Cordon            result = getOutgoingCall();
2448b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
2458b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        if (result == null) {
2468b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            result = getFirstCallWithState(Call.State.ACTIVE);
2478b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
2487fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        if (result == null) {
2497fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            result = getDisconnectingCall();
2507fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        }
2517fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        if (result == null) {
2527fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            result = getDisconnectedCall();
2537fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        }
2548b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        return result;
2558b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    }
2568b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
25714dbc3f0ca3a7998c9c5d28aba637487724f529fSantos Cordon    public Call getCall(int callId) {
25814dbc3f0ca3a7998c9c5d28aba637487724f529fSantos Cordon        return mCallMap.get(callId);
25914dbc3f0ca3a7998c9c5d28aba637487724f529fSantos Cordon    }
26014dbc3f0ca3a7998c9c5d28aba637487724f529fSantos Cordon
261150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    public boolean existsLiveCall() {
262a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        for (Call call : mCallMap.values()) {
263150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon            if (!isCallDead(call)) {
264150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon                return true;
265150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon            }
266150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        }
267150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        return false;
268150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    }
269150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon
2708b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public ArrayList<String> getTextResponses(int callId) {
2718b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        return mCallTextReponsesMap.get(callId);
27210196fd2f7cc922693e2a7c6c932725a52157943Christine Chen    }
27310196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
274150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    /**
275150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon     * Returns first call found in the call map with the specified state.
276150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon     */
277150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    public Call getFirstCallWithState(int state) {
278efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        return getCallWithState(state, 0);
279efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon    }
280efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon
281efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon    /**
282efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon     * Returns the [position]th call found in the call map with the specified state.
283046386ed5ae615c8d83bb5a9eccc15e5f79b61ccChristine Chen     * TODO: Improve this logic to sort by call time.
284efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon     */
285efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon    public Call getCallWithState(int state, int positionToFind) {
286150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        Call retval = null;
287efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon        int position = 0;
288150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon        for (Call call : mCallMap.values()) {
289150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon            if (call.getState() == state) {
290efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon                if (position >= positionToFind) {
291efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon                    retval = call;
292efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon                    break;
293efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon                } else {
294efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon                    position++;
295efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon                }
296a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon            }
297a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        }
298a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
299a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        return retval;
300a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    }
301a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
302a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    /**
3033c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon     * This is called when the service disconnects, either expectedly or unexpectedly.
3043c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon     * For the expected case, it's because we have no calls left.  For the unexpected case,
3053c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon     * it is likely a crash of phone and we need to clean up our calls manually.  Without phone,
3063c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon     * there can be no active calls, so this is relatively safe thing to do.
3073c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon     */
3083c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon    public void clearOnDisconnect() {
3093c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon        for (Call call : mCallMap.values()) {
3103c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon            final int state = call.getState();
3113c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon            if (state != Call.State.IDLE &&
3123c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon                    state != Call.State.INVALID &&
3133c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon                    state != Call.State.DISCONNECTED) {
314d7effd30eca546cabb5f1d70858b4038fa4a31c3Santos Cordon
3153c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon                call.setState(Call.State.DISCONNECTED);
316d7effd30eca546cabb5f1d70858b4038fa4a31c3Santos Cordon                call.setDisconnectCause(DisconnectCause.UNKNOWN);
3173c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon                updateCallInMap(call);
3183c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon            }
3193c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon        }
3203c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon        notifyListenersOfChange();
3213c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon    }
3223c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon
3233c5581a67ba89fd96fc19e64f6c4780d0a58f640Santos Cordon    /**
324a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * Sends a generic notification to all listeners that something has changed.
325a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * It is up to the listeners to call back to determine what changed.
326a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     */
327a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    private void notifyListenersOfChange() {
328a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        for (Listener listener : mListeners) {
329a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon            listener.onCallListChange(this);
330a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        }
33196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon    }
33296b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
3337fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon    private void notifyListenersOfDisconnect(Call call) {
3347fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        for (Listener listener : mListeners) {
3357fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            listener.onDisconnect(call);
3367fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        }
3377fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon    }
3387fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon
3397fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon    /**
3407fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon     * Updates the call entry in the local map.
3417fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon     * @return false if no call previously existed and no call was added, otherwise true.
3427fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon     */
3437fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon    private boolean updateCallInMap(Call call) {
34496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon        Preconditions.checkNotNull(call);
34596b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
3467fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        boolean updated = false;
3477fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon
34896b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon        final Integer id = new Integer(call.getCallId());
34996b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
350a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        if (call.getState() == Call.State.DISCONNECTED) {
3511df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon            // update existing (but do not add!!) disconnected calls
3521df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon            if (mCallMap.containsKey(id)) {
353a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
3541df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon                // For disconnected calls, we want to keep them alive for a few seconds so that the
3551df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon                // UI has a chance to display anything it needs when a call is disconnected.
3561df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon
3571df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon                // Set up a timer to destroy the call after X seconds.
3581df52df7a0248814fbd4575103059a8b427f5d9aSantos Cordon                final Message msg = mHandler.obtainMessage(EVENT_DISCONNECTED_TIMEOUT, call);
359ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                mHandler.sendMessageDelayed(msg, getDelayForDisconnect(call));
360a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
361a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon                mCallMap.put(id, call);
3627fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon                updated = true;
363a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon            }
364a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        } else if (!isCallDead(call)) {
365a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon            mCallMap.put(id, call);
3667fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            updated = true;
367a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        } else if (mCallMap.containsKey(id)) {
368a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon            mCallMap.remove(id);
3697fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon            updated = true;
37096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon        }
3717fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon
3727fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        return updated;
37396b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon    }
37496b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon
375ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon    private int getDelayForDisconnect(Call call) {
376ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon        Preconditions.checkState(call.getState() == Call.State.DISCONNECTED);
377ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon
378ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon
379ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon        final Call.DisconnectCause cause = call.getDisconnectCause();
380ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon        final int delay;
381ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon        switch (cause) {
382ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon            case LOCAL:
383ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                delay = DISCONNECTED_CALL_SHORT_TIMEOUT_MS;
384ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                break;
385ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon            case NORMAL:
386d7effd30eca546cabb5f1d70858b4038fa4a31c3Santos Cordon            case UNKNOWN:
387ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                delay = DISCONNECTED_CALL_MEDIUM_TIMEOUT_MS;
388ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                break;
389ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon            case INCOMING_REJECTED:
390ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon            case INCOMING_MISSED:
391ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                // no delay for missed/rejected incoming calls
392ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                delay = 0;
393ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                break;
394ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon            default:
395ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                delay = DISCONNECTED_CALL_LONG_TIMEOUT_MS;
396ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon                break;
397ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon        }
398ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon
399ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon        return delay;
400ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon    }
401ea83891eb10811d5020cc5fdaf34b711012dab32Santos Cordon
40210196fd2f7cc922693e2a7c6c932725a52157943Christine Chen    private void updateCallTextMap(Call call, List<String> textResponses) {
40310196fd2f7cc922693e2a7c6c932725a52157943Christine Chen        Preconditions.checkNotNull(call);
40410196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
40510196fd2f7cc922693e2a7c6c932725a52157943Christine Chen        final Integer id = new Integer(call.getCallId());
40610196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
40710196fd2f7cc922693e2a7c6c932725a52157943Christine Chen        if (!isCallDead(call)) {
40810196fd2f7cc922693e2a7c6c932725a52157943Christine Chen            if (textResponses != null) {
40910196fd2f7cc922693e2a7c6c932725a52157943Christine Chen                mCallTextReponsesMap.put(id, (ArrayList<String>) textResponses);
41010196fd2f7cc922693e2a7c6c932725a52157943Christine Chen            }
41110196fd2f7cc922693e2a7c6c932725a52157943Christine Chen        } else if (mCallMap.containsKey(id)) {
41210196fd2f7cc922693e2a7c6c932725a52157943Christine Chen            mCallTextReponsesMap.remove(id);
41310196fd2f7cc922693e2a7c6c932725a52157943Christine Chen        }
41410196fd2f7cc922693e2a7c6c932725a52157943Christine Chen    }
41510196fd2f7cc922693e2a7c6c932725a52157943Christine Chen
416a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    private boolean isCallDead(Call call) {
41796b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon        final int state = call.getState();
418a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon        return Call.State.IDLE == state || Call.State.INVALID == state;
419a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    }
420a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon
421671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon    /**
422a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon     * Sets up a call for deletion and notifies listeners of change.
423a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon     */
424a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    private void finishDisconnectedCall(Call call) {
425a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        call.setState(Call.State.IDLE);
426a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        updateCallInMap(call);
427a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        notifyListenersOfChange();
428a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    }
429a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
430a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    /**
431a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon     * Handles the timeout for destroying disconnected calls.
432a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon     */
433a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    private Handler mHandler = new Handler() {
434a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        @Override
435a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        public void handleMessage(Message msg) {
436a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon            switch (msg.what) {
437a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon                case EVENT_DISCONNECTED_TIMEOUT:
4381a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    Log.d(this, "EVENT_DISCONNECTED_TIMEOUT ", msg.obj);
439a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon                    finishDisconnectedCall((Call) msg.obj);
440a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon                    break;
441a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon                default:
4421a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    Log.wtf(this, "Message not expected: " + msg.what);
443a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon                    break;
444a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon            }
445a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon        }
446a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    };
447a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon
448a12f2589f424e26c63c8ee5b6fad89e30b69d7fbSantos Cordon    /**
449a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * Listener interface for any class that wants to be notified of changes
450a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     * to the call list.
451a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon     */
452a012c22dfbfedffe2e751f9b1ab776baa325a26fSantos Cordon    public interface Listener {
4537fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        /**
4547fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * Called when a new incoming call comes in.
4557fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * This is the only method that gets called for incoming calls. Listeners
4567fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * that want to perform an action on incoming call should respond in this method
4577fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * because {@link #onCallListChange} does not automatically get called for
4587fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * incoming calls.
4597fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         */
4608b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        public void onIncomingCall(Call call);
4617fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon
4627fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        /**
4637fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * Called anytime there are changes to the call list.  The change can be switching call
4647fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * states, updating information, etc. This method will NOT be called for new incoming
4657fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * calls and for calls that switch to disconnected state. Listeners must add actions
4667fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * to those method implementations if they want to deal with those actions.
4677fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         */
4687fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        public void onCallListChange(CallList callList);
4697fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon
4707fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        /**
4717fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * Called when a call switches to the disconnected state.  This is the only method
4727fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         * that will get called upon disconnection.
4737fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon         */
4747fff6a25f65e0949c8e2682d6470cf065e76a63fSantos Cordon        public void onDisconnect(Call call);
4758b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    }
4768b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
4778b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng    public interface CallUpdateListener {
4788b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        // TODO: refactor and limit arg to be call state.  Caller info is not needed.
4798b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        public void onCallStateChanged(Call call);
48096b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon    }
48196b8ba57ac2399336478ffa7a2ccc9423bda0a52Santos Cordon}
482