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