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