Home | History | Annotate | Download | only in phone
      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 
     61     public ManageConferenceUtils(InCallScreen inCallScreen, CallManager cm) {
     62         if (DBG) log("ManageConferenceUtils constructor...");
     63         mInCallScreen = inCallScreen;
     64         mCM = cm;
     65     }
     66 
     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      */
    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      */
    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      */
    124     public void stopConferenceTime() {
    125         if (mConferenceTime != null) {
    126             mConferenceTime.stop();
    127         }
    128     }
    129 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    339     private void log(String msg) {
    340         Log.d(LOG_TAG, msg);
    341     }
    342 }
    343