| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.phone; |
| |
| import android.os.SystemProperties; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewStub; |
| import android.widget.Button; |
| import android.widget.Chronometer; |
| import android.widget.ImageButton; |
| import android.widget.TextView; |
| |
| import com.android.internal.telephony.CallerInfo; |
| import com.android.internal.telephony.CallerInfoAsyncQuery; |
| import com.android.internal.telephony.CallManager; |
| import com.android.internal.telephony.Connection; |
| |
| import java.util.List; |
| |
| |
| /** |
| * Helper class to initialize and run the InCallScreen's "Manage conference" UI. |
| */ |
| public class ManageConferenceUtils { |
| private static final String LOG_TAG = "ManageConferenceUtils"; |
| private static final boolean DBG = |
| (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); |
| |
| /** |
| * CallerInfoAsyncQuery.OnQueryCompleteListener implementation. |
| * |
| * This object listens for results from the caller-id info queries we |
| * fire off in updateManageConferenceRow(), and updates the |
| * corresponding conference row. |
| */ |
| private final class QueryCompleteListener |
| implements CallerInfoAsyncQuery.OnQueryCompleteListener { |
| private final int mConferencCallListIndex; |
| |
| public QueryCompleteListener(int index) { |
| mConferencCallListIndex = index; |
| } |
| |
| @Override |
| public void onQueryComplete(int token, Object cookie, CallerInfo ci) { |
| if (DBG) log("callerinfo query complete, updating UI." + ci); |
| |
| Connection connection = (Connection) cookie; |
| int presentation = connection.getNumberPresentation(); |
| |
| // get the viewgroup (conference call list item) and make it visible |
| ViewGroup viewGroup = mConferenceCallList[mConferencCallListIndex]; |
| viewGroup.setVisibility(View.VISIBLE); |
| |
| // update the list item with this information. |
| displayCallerInfoForConferenceRow(ci, presentation, |
| (TextView) viewGroup.findViewById(R.id.conferenceCallerName), |
| (TextView) viewGroup.findViewById(R.id.conferenceCallerNumberType), |
| (TextView) viewGroup.findViewById(R.id.conferenceCallerNumber)); |
| } |
| } |
| |
| private InCallScreen mInCallScreen; |
| private CallManager mCM; |
| |
| // "Manage conference" UI elements and state |
| private ViewGroup mManageConferencePanel; |
| private View mButtonManageConferenceDone; |
| private ViewGroup[] mConferenceCallList; |
| private int mNumCallersInConference; |
| private Chronometer mConferenceTime; |
| |
| // See CallTracker.MAX_CONNECTIONS_PER_CALL |
| private static final int MAX_CALLERS_IN_CONFERENCE = 5; |
| |
| public ManageConferenceUtils(InCallScreen inCallScreen, CallManager cm) { |
| if (DBG) log("ManageConferenceUtils constructor..."); |
| mInCallScreen = inCallScreen; |
| mCM = cm; |
| } |
| |
| public void initManageConferencePanel() { |
| if (DBG) log("initManageConferencePanel()..."); |
| if (mManageConferencePanel == null) { |
| if (DBG) log("initManageConferencePanel: first-time initialization!"); |
| |
| // Inflate the ViewStub, look up and initialize the UI elements. |
| ViewStub stub = (ViewStub) mInCallScreen.findViewById(R.id.manageConferencePanelStub); |
| stub.inflate(); |
| |
| mManageConferencePanel = |
| (ViewGroup) mInCallScreen.findViewById(R.id.manageConferencePanel); |
| if (mManageConferencePanel == null) { |
| throw new IllegalStateException("Couldn't find manageConferencePanel!"); |
| } |
| |
| // set up the Conference Call chronometer |
| mConferenceTime = |
| (Chronometer) mInCallScreen.findViewById(R.id.manageConferencePanelHeader); |
| mConferenceTime.setFormat(mInCallScreen.getString(R.string.caller_manage_header)); |
| |
| // Create list of conference call widgets |
| mConferenceCallList = new ViewGroup[MAX_CALLERS_IN_CONFERENCE]; |
| |
| final int[] viewGroupIdList = { R.id.caller0, R.id.caller1, R.id.caller2, |
| R.id.caller3, R.id.caller4 }; |
| for (int i = 0; i < MAX_CALLERS_IN_CONFERENCE; i++) { |
| mConferenceCallList[i] = |
| (ViewGroup) mInCallScreen.findViewById(viewGroupIdList[i]); |
| } |
| |
| mButtonManageConferenceDone = mInCallScreen.findViewById(R.id.manage_done); |
| mButtonManageConferenceDone.setOnClickListener(mInCallScreen); |
| } |
| } |
| |
| /** |
| * Shows or hides the manageConferencePanel. |
| */ |
| public void setPanelVisible(boolean visible) { |
| if (mManageConferencePanel != null) { |
| mManageConferencePanel.setVisibility(visible ? View.VISIBLE : View.GONE); |
| } |
| } |
| |
| /** |
| * Starts the "conference time" chronometer. |
| */ |
| public void startConferenceTime(long base) { |
| if (mConferenceTime != null) { |
| mConferenceTime.setBase(base); |
| mConferenceTime.start(); |
| } |
| } |
| |
| /** |
| * Stops the "conference time" chronometer. |
| */ |
| public void stopConferenceTime() { |
| if (mConferenceTime != null) { |
| mConferenceTime.stop(); |
| } |
| } |
| |
| public int getNumCallersInConference() { |
| return mNumCallersInConference; |
| } |
| |
| /** |
| * Updates the "Manage conference" UI based on the specified List of |
| * connections. |
| * |
| * @param connections the List of connections belonging to |
| * the current foreground call; size must be greater than 1 |
| * (or it wouldn't be a conference call in the first place.) |
| */ |
| public void updateManageConferencePanel(List<Connection> connections) { |
| mNumCallersInConference = connections.size(); |
| if (DBG) log("updateManageConferencePanel()... num connections in conference = " |
| + mNumCallersInConference); |
| |
| // Can we give the user the option to separate out ("go private with") a single |
| // caller from this conference? |
| final boolean hasActiveCall = mCM.hasActiveFgCall(); |
| final boolean hasHoldingCall = mCM.hasActiveBgCall(); |
| boolean canSeparate = !(hasActiveCall && hasHoldingCall); |
| |
| for (int i = 0; i < MAX_CALLERS_IN_CONFERENCE; i++) { |
| if (i < mNumCallersInConference) { |
| // Fill in the row in the UI for this caller. |
| Connection connection = (Connection) connections.get(i); |
| updateManageConferenceRow(i, connection, canSeparate); |
| } else { |
| // Blank out this row in the UI |
| updateManageConferenceRow(i, null, false); |
| } |
| } |
| } |
| |
| /** |
| * Updates a single row of the "Manage conference" UI. (One row in this |
| * UI represents a single caller in the conference.) |
| * |
| * @param i the row to update |
| * @param connection the Connection corresponding to this caller. |
| * If null, that means this is an "empty slot" in the conference, |
| * so hide this row in the UI. |
| * @param canSeparate if true, show a "Separate" (i.e. "Private") button |
| * on this row in the UI. |
| */ |
| public void updateManageConferenceRow(final int i, |
| final Connection connection, |
| boolean canSeparate) { |
| if (DBG) log("updateManageConferenceRow(" + i + ")... connection = " + connection); |
| |
| if (connection != null) { |
| // Activate this row of the Manage conference panel: |
| mConferenceCallList[i].setVisibility(View.VISIBLE); |
| |
| // get the relevant children views |
| View endButton = mConferenceCallList[i].findViewById(R.id.conferenceCallerDisconnect); |
| View separateButton = mConferenceCallList[i].findViewById( |
| R.id.conferenceCallerSeparate); |
| TextView nameTextView = (TextView) mConferenceCallList[i].findViewById( |
| R.id.conferenceCallerName); |
| TextView numberTextView = (TextView) mConferenceCallList[i].findViewById( |
| R.id.conferenceCallerNumber); |
| TextView numberTypeTextView = (TextView) mConferenceCallList[i].findViewById( |
| R.id.conferenceCallerNumberType); |
| |
| if (DBG) log("- button: " + endButton + ", nameTextView: " + nameTextView); |
| |
| // Hook up this row's buttons. |
| View.OnClickListener endThisConnection = new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| endConferenceConnection(i, connection); |
| PhoneGlobals.getInstance().pokeUserActivity(); |
| } |
| }; |
| endButton.setOnClickListener(endThisConnection); |
| // |
| if (canSeparate) { |
| View.OnClickListener separateThisConnection = new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| separateConferenceConnection(i, connection); |
| PhoneGlobals.getInstance().pokeUserActivity(); |
| } |
| }; |
| separateButton.setOnClickListener(separateThisConnection); |
| separateButton.setVisibility(View.VISIBLE); |
| } else { |
| separateButton.setVisibility(View.INVISIBLE); |
| } |
| |
| // Name/number for this caller. |
| QueryCompleteListener listener = new QueryCompleteListener(i); |
| PhoneUtils.CallerInfoToken info = |
| PhoneUtils.startGetCallerInfo(mInCallScreen, |
| connection, listener, connection); |
| if (DBG) log(" - got info from startGetCallerInfo(): " + info); |
| |
| // display the CallerInfo. |
| displayCallerInfoForConferenceRow(info.currentInfo, connection.getNumberPresentation(), |
| nameTextView, numberTypeTextView, numberTextView); |
| } else { |
| // Disable this row of the Manage conference panel: |
| mConferenceCallList[i].setVisibility(View.GONE); |
| } |
| } |
| |
| /** |
| * Helper function to fill out the Conference Call(er) information |
| * for each item in the "Manage Conference Call" list. |
| * |
| * @param presentation presentation specified by {@link Connection}. |
| */ |
| public final void displayCallerInfoForConferenceRow(CallerInfo ci, int presentation, |
| TextView nameTextView, TextView numberTypeTextView, TextView numberTextView) { |
| // gather the correct name and number information. |
| String callerName = ""; |
| String callerNumber = ""; |
| String callerNumberType = ""; |
| if (ci != null) { |
| callerName = ci.name; |
| if (TextUtils.isEmpty(callerName)) { |
| // Do similar fallback as CallCard does. |
| // See also CallCard#updateDisplayForPerson(). |
| if (TextUtils.isEmpty(ci.phoneNumber)) { |
| callerName = PhoneUtils.getPresentationString(mInCallScreen, presentation); |
| } else if (!TextUtils.isEmpty(ci.cnapName)) { |
| // No name, but we do have a valid CNAP name, so use that. |
| callerName = ci.cnapName; |
| } else { |
| callerName = ci.phoneNumber; |
| } |
| } else { |
| callerNumber = ci.phoneNumber; |
| callerNumberType = ci.phoneLabel; |
| } |
| } |
| |
| // set the caller name |
| nameTextView.setText(callerName); |
| |
| // set the caller number in subscript, or make the field disappear. |
| if (TextUtils.isEmpty(callerNumber)) { |
| numberTextView.setVisibility(View.GONE); |
| numberTypeTextView.setVisibility(View.GONE); |
| } else { |
| numberTextView.setVisibility(View.VISIBLE); |
| numberTextView.setText(callerNumber); |
| numberTypeTextView.setVisibility(View.VISIBLE); |
| numberTypeTextView.setText(callerNumberType); |
| } |
| } |
| |
| /** |
| * Ends the specified connection on a conference call. This method is |
| * run (via a closure containing a row index and Connection) when the |
| * user clicks the "End" button on a specific row in the Manage |
| * conference UI. |
| */ |
| public void endConferenceConnection(int i, Connection connection) { |
| if (DBG) log("===> ENDING conference connection " + i |
| + ": Connection " + connection); |
| // The actual work of ending the connection: |
| PhoneUtils.hangup(connection); |
| // No need to manually update the "Manage conference" UI here; |
| // that'll happen automatically very soon (when we get the |
| // onDisconnect() callback triggered by this hangup() call.) |
| } |
| |
| /** |
| * Separates out the specified connection on a conference call. This |
| * method is run (via a closure containing a row index and Connection) |
| * when the user clicks the "Separate" (i.e. "Private") button on a |
| * specific row in the Manage conference UI. |
| */ |
| public void separateConferenceConnection(int i, Connection connection) { |
| if (DBG) log("===> SEPARATING conference connection " + i |
| + ": Connection " + connection); |
| |
| PhoneUtils.separateCall(connection); |
| |
| // Note that separateCall() automagically makes the |
| // newly-separated call into the foreground call (which is the |
| // desired UI), so there's no need to do any further |
| // call-switching here. |
| // There's also no need to manually update (or hide) the "Manage |
| // conference" UI; that'll happen on its own in a moment (when we |
| // get the phone state change event triggered by the call to |
| // separateCall().) |
| } |
| |
| |
| private void log(String msg) { |
| Log.d(LOG_TAG, msg); |
| } |
| } |