• 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 
35 import java.util.List;
36 
37 
38 /**
39  * Helper class to initialize and run the InCallScreen's "Manage conference" UI.
40  */
41 public class ManageConferenceUtils {
42     private static final String LOG_TAG = "ManageConferenceUtils";
43     private static final boolean DBG =
44             (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
45 
46     /**
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 
QueryCompleteListener(int index)57         public QueryCompleteListener(int index) {
58             mConferencCallListIndex = index;
59         }
60 
61         @Override
onQueryComplete(int token, Object cookie, CallerInfo ci)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 
80     private InCallScreen mInCallScreen;
81     private CallManager mCM;
82 
83     // "Manage conference" UI elements and state
84     private ViewGroup mManageConferencePanel;
85     private View mButtonManageConferenceDone;
86     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 
ManageConferenceUtils(InCallScreen inCallScreen, CallManager cm)93     public ManageConferenceUtils(InCallScreen inCallScreen, CallManager cm) {
94         if (DBG) log("ManageConferenceUtils constructor...");
95         mInCallScreen = inCallScreen;
96         mCM = cm;
97     }
98 
initManageConferencePanel()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 
129             mButtonManageConferenceDone = mInCallScreen.findViewById(R.id.manage_done);
130             mButtonManageConferenceDone.setOnClickListener(mInCallScreen);
131         }
132     }
133 
134     /**
135      * Shows or hides the manageConferencePanel.
136      */
setPanelVisible(boolean visible)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      */
startConferenceTime(long base)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      */
stopConferenceTime()156     public void stopConferenceTime() {
157         if (mConferenceTime != null) {
158             mConferenceTime.stop();
159         }
160     }
161 
getNumCallersInConference()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      */
updateManageConferencePanel(List<Connection> connections)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?
181         final boolean hasActiveCall = mCM.hasActiveFgCall();
182         final boolean hasHoldingCall = mCM.hasActiveBgCall();
183         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      */
updateManageConferenceRow(final int i, final Connection connection, boolean canSeparate)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
218             View endButton = mConferenceCallList[i].findViewById(R.id.conferenceCallerDisconnect);
219             View separateButton = mConferenceCallList[i].findViewById(
220                     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() {
232                     @Override
233                     public void onClick(View v) {
234                         endConferenceConnection(i, connection);
235                         PhoneApp.getInstance().pokeUserActivity();
236                     }
237                 };
238             endButton.setOnClickListener(endThisConnection);
239             //
240             if (canSeparate) {
241                 View.OnClickListener separateThisConnection = new View.OnClickListener() {
242                         @Override
243                         public void onClick(View v) {
244                             separateConferenceConnection(i, connection);
245                             PhoneApp.getInstance().pokeUserActivity();
246                         }
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.
255             QueryCompleteListener listener = new QueryCompleteListener(i);
256             PhoneUtils.CallerInfoToken info =
257                     PhoneUtils.startGetCallerInfo(mInCallScreen,
258                             connection, listener, connection);
259             if (DBG) log("  - got info from startGetCallerInfo(): " + info);
260 
261             // display the CallerInfo.
262             displayCallerInfoForConferenceRow(info.currentInfo, connection.getNumberPresentation(),
263                     nameTextView, numberTypeTextView, numberTextView);
264         } 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.
273      *
274      * @param presentation presentation specified by {@link Connection}.
275      */
displayCallerInfoForConferenceRow(CallerInfo ci, int presentation, TextView nameTextView, TextView numberTypeTextView, TextView numberTextView)276     public final void displayCallerInfoForConferenceRow(CallerInfo ci, int presentation,
277             TextView nameTextView, TextView numberTypeTextView, TextView numberTextView) {
278         // 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)) {
285                 // 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;
294                 }
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      */
endConferenceConnection(int i, Connection connection)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      */
separateConferenceConnection(int i, Connection connection)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 
354 
log(String msg)355     private void log(String msg) {
356         Log.d(LOG_TAG, msg);
357     }
358 }
359