CallList.java revision 150a5c58c67f230c8fd7293b180bbf50aa761480
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.incallui;
18
19import com.google.android.collect.Lists;
20import com.google.android.collect.Maps;
21import com.google.android.collect.Sets;
22import com.google.common.base.Preconditions;
23import com.google.common.collect.ImmutableList;
24
25import android.util.Log;
26
27import com.android.services.telephony.common.Call;
28
29import java.util.HashMap;
30import java.util.List;
31import java.util.Set;
32
33/**
34 * Maintains the list of active calls received from CallHandlerService.
35 * TODO(klp): This class should be used by InCallUI to read about
36 * changes to calls.
37 */
38public class CallList {
39    private static String TAG = CallList.class.getSimpleName();
40
41    private static CallList sInstance;
42
43    private final HashMap<Integer, Call> mCallMap = Maps.newHashMap();
44    private final Set<Listener> mListeners = Sets.newArraySet();
45
46    /**
47     * Static singleton accessor method.
48     */
49    public static synchronized CallList getInstance() {
50        if (sInstance == null) {
51            sInstance = new CallList();
52        }
53        return sInstance;
54    }
55
56    /**
57     * Private constructor.  Instance should only be acquired through getInstance().
58     */
59    private CallList() {
60    }
61
62    /**
63     * Called when a single call has changed.
64     */
65    public void onUpdate(Call call) {
66        updateCallInMap(call);
67
68        notifyListenersOfChange();
69    }
70
71    /**
72     * Called when multiple calls have changed.
73     */
74    public void onUpdate(List<Call> callsToUpdate) {
75        Preconditions.checkNotNull(callsToUpdate);
76        for (Call call : callsToUpdate) {
77            updateCallInMap(call);
78        }
79
80        notifyListenersOfChange();
81    }
82
83    public void addListener(Listener listener) {
84        Preconditions.checkNotNull(listener);
85
86        mListeners.add(listener);
87
88        // Let the listener know about the active calls immediately.
89        listener.onCallListChange(this);
90    }
91
92    public void removeListener(Listener listener) {
93        Preconditions.checkNotNull(listener);
94        mListeners.remove(listener);
95    }
96
97    /**
98     * TODO(klp): Change so that this function is not needed. Instead of assuming there is an active
99     * call, the code should rely on the status of a specific Call and allow the presenters to
100     * update the Call object when the active call changes.
101     */
102    public Call getIncomingOrActive() {
103        Call retval = getIncomingCall();
104        if (retval == null) {
105            retval = getFirstCallWithState(Call.State.ACTIVE);
106        }
107        return retval;
108    }
109
110    public Call getBackgroundCall() {
111        return getFirstCallWithState(Call.State.ONHOLD);
112    }
113
114    public Call getIncomingCall() {
115        return getFirstCallWithState(Call.State.INCOMING);
116    }
117
118    public boolean existsLiveCall() {
119        for (Call call : mCallMap.values()) {
120            if (!isCallDead(call)) {
121                return true;
122            }
123        }
124        return false;
125    }
126
127    /**
128     * Returns first call found in the call map with the specified state.
129     */
130    public Call getFirstCallWithState(int state) {
131        Call retval = null;
132        for (Call call : mCallMap.values()) {
133            if (call.getState() == state) {
134                retval = call;
135                break;
136            }
137        }
138
139        return retval;
140    }
141
142    /**
143     * Sends a generic notification to all listeners that something has changed.
144     * It is up to the listeners to call back to determine what changed.
145     */
146    private void notifyListenersOfChange() {
147        for (Listener listener : mListeners) {
148            listener.onCallListChange(this);
149        }
150    }
151
152    private void updateCallInMap(Call call) {
153        Preconditions.checkNotNull(call);
154
155        final Integer id = new Integer(call.getCallId());
156
157        if (!isCallDead(call)) {
158            mCallMap.put(id, call);
159        } else if (mCallMap.containsKey(id)) {
160            mCallMap.remove(id);
161        }
162    }
163
164    private boolean isCallDead(Call call) {
165        final int state = call.getState();
166        return Call.State.IDLE == state || Call.State.INVALID == state;
167    }
168
169    /**
170     * Listener interface for any class that wants to be notified of changes
171     * to the call list.
172     */
173    public interface Listener {
174        public void onCallListChange(CallList callList);
175    }
176}
177