blob: 62e9a9952e3b6b3e8c7a11a782b461ab160dc142 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2009 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.phone;
18
19import android.os.SystemProperties;
20import android.text.TextUtils;
21import android.util.Log;
22import android.view.View;
23import android.view.ViewGroup;
24import android.view.ViewStub;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070025import android.widget.Chronometer;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070026import android.widget.TextView;
27
28import com.android.internal.telephony.CallerInfo;
29import com.android.internal.telephony.CallerInfoAsyncQuery;
30import com.android.internal.telephony.CallManager;
31import com.android.internal.telephony.Connection;
32
33import java.util.List;
34
35
36/**
37 * Helper class to initialize and run the InCallScreen's "Manage conference" UI.
38 */
39public class ManageConferenceUtils {
40 private static final String LOG_TAG = "ManageConferenceUtils";
41 private static final boolean DBG =
42 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
43
44 /**
45 * CallerInfoAsyncQuery.OnQueryCompleteListener implementation.
46 *
47 * This object listens for results from the caller-id info queries we
48 * fire off in updateManageConferenceRow(), and updates the
49 * corresponding conference row.
50 */
51 private final class QueryCompleteListener
52 implements CallerInfoAsyncQuery.OnQueryCompleteListener {
53 private final int mConferencCallListIndex;
54
55 public QueryCompleteListener(int index) {
56 mConferencCallListIndex = index;
57 }
58
59 @Override
60 public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
61 if (DBG) log("callerinfo query complete, updating UI." + ci);
62
63 Connection connection = (Connection) cookie;
64 int presentation = connection.getNumberPresentation();
65
66 // get the viewgroup (conference call list item) and make it visible
67 ViewGroup viewGroup = mConferenceCallList[mConferencCallListIndex];
68 viewGroup.setVisibility(View.VISIBLE);
69
70 // update the list item with this information.
71 displayCallerInfoForConferenceRow(ci, presentation,
72 (TextView) viewGroup.findViewById(R.id.conferenceCallerName),
73 (TextView) viewGroup.findViewById(R.id.conferenceCallerNumberType),
74 (TextView) viewGroup.findViewById(R.id.conferenceCallerNumber));
75 }
76 }
77
78 private InCallScreen mInCallScreen;
79 private CallManager mCM;
80
81 // "Manage conference" UI elements and state
82 private ViewGroup mManageConferencePanel;
83 private View mButtonManageConferenceDone;
84 private ViewGroup[] mConferenceCallList;
85 private int mNumCallersInConference;
86 private Chronometer mConferenceTime;
87
88 // See CallTracker.MAX_CONNECTIONS_PER_CALL
89 private static final int MAX_CALLERS_IN_CONFERENCE = 5;
90
91 public ManageConferenceUtils(InCallScreen inCallScreen, CallManager cm) {
92 if (DBG) log("ManageConferenceUtils constructor...");
93 mInCallScreen = inCallScreen;
94 mCM = cm;
95 }
96
97 public void initManageConferencePanel() {
98 if (DBG) log("initManageConferencePanel()...");
99 if (mManageConferencePanel == null) {
100 if (DBG) log("initManageConferencePanel: first-time initialization!");
101
102 // Inflate the ViewStub, look up and initialize the UI elements.
103 ViewStub stub = (ViewStub) mInCallScreen.findViewById(R.id.manageConferencePanelStub);
104 stub.inflate();
105
106 mManageConferencePanel =
107 (ViewGroup) mInCallScreen.findViewById(R.id.manageConferencePanel);
108 if (mManageConferencePanel == null) {
109 throw new IllegalStateException("Couldn't find manageConferencePanel!");
110 }
111
112 // set up the Conference Call chronometer
113 mConferenceTime =
114 (Chronometer) mInCallScreen.findViewById(R.id.manageConferencePanelHeader);
115 mConferenceTime.setFormat(mInCallScreen.getString(R.string.caller_manage_header));
116
117 // Create list of conference call widgets
118 mConferenceCallList = new ViewGroup[MAX_CALLERS_IN_CONFERENCE];
119
120 final int[] viewGroupIdList = { R.id.caller0, R.id.caller1, R.id.caller2,
121 R.id.caller3, R.id.caller4 };
122 for (int i = 0; i < MAX_CALLERS_IN_CONFERENCE; i++) {
123 mConferenceCallList[i] =
124 (ViewGroup) mInCallScreen.findViewById(viewGroupIdList[i]);
125 }
126
127 mButtonManageConferenceDone = mInCallScreen.findViewById(R.id.manage_done);
128 mButtonManageConferenceDone.setOnClickListener(mInCallScreen);
129 }
130 }
131
132 /**
133 * Shows or hides the manageConferencePanel.
134 */
135 public void setPanelVisible(boolean visible) {
136 if (mManageConferencePanel != null) {
137 mManageConferencePanel.setVisibility(visible ? View.VISIBLE : View.GONE);
138 }
139 }
140
141 /**
142 * Starts the "conference time" chronometer.
143 */
144 public void startConferenceTime(long base) {
145 if (mConferenceTime != null) {
146 mConferenceTime.setBase(base);
147 mConferenceTime.start();
148 }
149 }
150
151 /**
152 * Stops the "conference time" chronometer.
153 */
154 public void stopConferenceTime() {
155 if (mConferenceTime != null) {
156 mConferenceTime.stop();
157 }
158 }
159
160 public int getNumCallersInConference() {
161 return mNumCallersInConference;
162 }
163
164 /**
165 * Updates the "Manage conference" UI based on the specified List of
166 * connections.
167 *
168 * @param connections the List of connections belonging to
169 * the current foreground call; size must be greater than 1
170 * (or it wouldn't be a conference call in the first place.)
171 */
172 public void updateManageConferencePanel(List<Connection> connections) {
173 mNumCallersInConference = connections.size();
174 if (DBG) log("updateManageConferencePanel()... num connections in conference = "
175 + mNumCallersInConference);
176
177 // Can we give the user the option to separate out ("go private with") a single
178 // caller from this conference?
179 final boolean hasActiveCall = mCM.hasActiveFgCall();
180 final boolean hasHoldingCall = mCM.hasActiveBgCall();
181 boolean canSeparate = !(hasActiveCall && hasHoldingCall);
182
183 for (int i = 0; i < MAX_CALLERS_IN_CONFERENCE; i++) {
184 if (i < mNumCallersInConference) {
185 // Fill in the row in the UI for this caller.
186 Connection connection = (Connection) connections.get(i);
187 updateManageConferenceRow(i, connection, canSeparate);
188 } else {
189 // Blank out this row in the UI
190 updateManageConferenceRow(i, null, false);
191 }
192 }
193 }
194
195 /**
196 * Updates a single row of the "Manage conference" UI. (One row in this
197 * UI represents a single caller in the conference.)
198 *
199 * @param i the row to update
200 * @param connection the Connection corresponding to this caller.
201 * If null, that means this is an "empty slot" in the conference,
202 * so hide this row in the UI.
203 * @param canSeparate if true, show a "Separate" (i.e. "Private") button
204 * on this row in the UI.
205 */
206 public void updateManageConferenceRow(final int i,
207 final Connection connection,
208 boolean canSeparate) {
209 if (DBG) log("updateManageConferenceRow(" + i + ")... connection = " + connection);
210
211 if (connection != null) {
212 // Activate this row of the Manage conference panel:
213 mConferenceCallList[i].setVisibility(View.VISIBLE);
214
215 // get the relevant children views
216 View endButton = mConferenceCallList[i].findViewById(R.id.conferenceCallerDisconnect);
217 View separateButton = mConferenceCallList[i].findViewById(
218 R.id.conferenceCallerSeparate);
219 TextView nameTextView = (TextView) mConferenceCallList[i].findViewById(
220 R.id.conferenceCallerName);
221 TextView numberTextView = (TextView) mConferenceCallList[i].findViewById(
222 R.id.conferenceCallerNumber);
223 TextView numberTypeTextView = (TextView) mConferenceCallList[i].findViewById(
224 R.id.conferenceCallerNumberType);
225
226 if (DBG) log("- button: " + endButton + ", nameTextView: " + nameTextView);
227
228 // Hook up this row's buttons.
229 View.OnClickListener endThisConnection = new View.OnClickListener() {
230 @Override
231 public void onClick(View v) {
232 endConferenceConnection(i, connection);
233 PhoneGlobals.getInstance().pokeUserActivity();
234 }
235 };
236 endButton.setOnClickListener(endThisConnection);
237 //
238 if (canSeparate) {
239 View.OnClickListener separateThisConnection = new View.OnClickListener() {
240 @Override
241 public void onClick(View v) {
242 separateConferenceConnection(i, connection);
243 PhoneGlobals.getInstance().pokeUserActivity();
244 }
245 };
246 separateButton.setOnClickListener(separateThisConnection);
247 separateButton.setVisibility(View.VISIBLE);
248 } else {
249 separateButton.setVisibility(View.INVISIBLE);
250 }
251
252 // Name/number for this caller.
253 QueryCompleteListener listener = new QueryCompleteListener(i);
254 PhoneUtils.CallerInfoToken info =
255 PhoneUtils.startGetCallerInfo(mInCallScreen,
256 connection, listener, connection);
257 if (DBG) log(" - got info from startGetCallerInfo(): " + info);
258
259 // display the CallerInfo.
260 displayCallerInfoForConferenceRow(info.currentInfo, connection.getNumberPresentation(),
261 nameTextView, numberTypeTextView, numberTextView);
262 } else {
263 // Disable this row of the Manage conference panel:
264 mConferenceCallList[i].setVisibility(View.GONE);
265 }
266 }
267
268 /**
269 * Helper function to fill out the Conference Call(er) information
270 * for each item in the "Manage Conference Call" list.
271 *
272 * @param presentation presentation specified by {@link Connection}.
273 */
274 public final void displayCallerInfoForConferenceRow(CallerInfo ci, int presentation,
275 TextView nameTextView, TextView numberTypeTextView, TextView numberTextView) {
276 // gather the correct name and number information.
277 String callerName = "";
278 String callerNumber = "";
279 String callerNumberType = "";
280 if (ci != null) {
281 callerName = ci.name;
282 if (TextUtils.isEmpty(callerName)) {
283 // Do similar fallback as CallCard does.
284 // See also CallCard#updateDisplayForPerson().
285 if (TextUtils.isEmpty(ci.phoneNumber)) {
286 callerName = PhoneUtils.getPresentationString(mInCallScreen, presentation);
287 } else if (!TextUtils.isEmpty(ci.cnapName)) {
288 // No name, but we do have a valid CNAP name, so use that.
289 callerName = ci.cnapName;
290 } else {
291 callerName = ci.phoneNumber;
292 }
293 } else {
294 callerNumber = ci.phoneNumber;
295 callerNumberType = ci.phoneLabel;
296 }
297 }
298
299 // set the caller name
300 nameTextView.setText(callerName);
301
302 // set the caller number in subscript, or make the field disappear.
303 if (TextUtils.isEmpty(callerNumber)) {
304 numberTextView.setVisibility(View.GONE);
305 numberTypeTextView.setVisibility(View.GONE);
306 } else {
307 numberTextView.setVisibility(View.VISIBLE);
308 numberTextView.setText(callerNumber);
309 numberTypeTextView.setVisibility(View.VISIBLE);
310 numberTypeTextView.setText(callerNumberType);
311 }
312 }
313
314 /**
315 * Ends the specified connection on a conference call. This method is
316 * run (via a closure containing a row index and Connection) when the
317 * user clicks the "End" button on a specific row in the Manage
318 * conference UI.
319 */
320 public void endConferenceConnection(int i, Connection connection) {
321 if (DBG) log("===> ENDING conference connection " + i
322 + ": Connection " + connection);
323 // The actual work of ending the connection:
324 PhoneUtils.hangup(connection);
325 // No need to manually update the "Manage conference" UI here;
326 // that'll happen automatically very soon (when we get the
327 // onDisconnect() callback triggered by this hangup() call.)
328 }
329
330 /**
331 * Separates out the specified connection on a conference call. This
332 * method is run (via a closure containing a row index and Connection)
333 * when the user clicks the "Separate" (i.e. "Private") button on a
334 * specific row in the Manage conference UI.
335 */
336 public void separateConferenceConnection(int i, Connection connection) {
337 if (DBG) log("===> SEPARATING conference connection " + i
338 + ": Connection " + connection);
339
340 PhoneUtils.separateCall(connection);
341
342 // Note that separateCall() automagically makes the
343 // newly-separated call into the foreground call (which is the
344 // desired UI), so there's no need to do any further
345 // call-switching here.
346 // There's also no need to manually update (or hide) the "Manage
347 // conference" UI; that'll happen on its own in a moment (when we
348 // get the phone state change event triggered by the call to
349 // separateCall().)
350 }
351
352
353 private void log(String msg) {
354 Log.d(LOG_TAG, msg);
355 }
356}