Home | History | Annotate | Download | only in sip
      1 /*
      2  * Copyright (C) 2010 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.example.android.sip;
     18 
     19 import android.app.Activity;
     20 import android.app.AlertDialog;
     21 import android.app.Dialog;
     22 import android.app.PendingIntent;
     23 import android.content.DialogInterface;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.SharedPreferences;
     27 import android.os.Bundle;
     28 import android.preference.PreferenceManager;
     29 import android.util.Log;
     30 import android.view.*;
     31 import android.net.sip.*;
     32 import android.widget.EditText;
     33 import android.widget.TextView;
     34 import android.widget.ToggleButton;
     35 
     36 import java.text.ParseException;
     37 
     38 /**
     39  * Handles all calling, receiving calls, and UI interaction in the WalkieTalkie app.
     40  */
     41 public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
     42 
     43     public String sipAddress = null;
     44 
     45     public SipManager manager = null;
     46     public SipProfile me = null;
     47     public SipAudioCall call = null;
     48     public IncomingCallReceiver callReceiver;
     49 
     50     private static final int CALL_ADDRESS = 1;
     51     private static final int SET_AUTH_INFO = 2;
     52     private static final int UPDATE_SETTINGS_DIALOG = 3;
     53     private static final int HANG_UP = 4;
     54 
     55 
     56     @Override
     57     public void onCreate(Bundle savedInstanceState) {
     58 
     59         super.onCreate(savedInstanceState);
     60         setContentView(R.layout.walkietalkie);
     61 
     62         ToggleButton pushToTalkButton = (ToggleButton) findViewById(R.id.pushToTalk);
     63         pushToTalkButton.setOnTouchListener(this);
     64 
     65         // Set up the intent filter.  This will be used to fire an
     66         // IncomingCallReceiver when someone calls the SIP address used by this
     67         // application.
     68         IntentFilter filter = new IntentFilter();
     69         filter.addAction("android.SipDemo.INCOMING_CALL");
     70         callReceiver = new IncomingCallReceiver();
     71         this.registerReceiver(callReceiver, filter);
     72 
     73         // "Push to talk" can be a serious pain when the screen keeps turning off.
     74         // Let's prevent that.
     75         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     76 
     77         initializeManager();
     78     }
     79 
     80     @Override
     81     public void onStart() {
     82         super.onStart();
     83         // When we get back from the preference setting Activity, assume
     84         // settings have changed, and re-login with new auth info.
     85         initializeManager();
     86     }
     87 
     88     @Override
     89     public void onDestroy() {
     90         super.onDestroy();
     91         if (call != null) {
     92             call.close();
     93         }
     94 
     95         closeLocalProfile();
     96 
     97         if (callReceiver != null) {
     98             this.unregisterReceiver(callReceiver);
     99         }
    100     }
    101 
    102     public void initializeManager() {
    103         if(manager == null) {
    104           manager = SipManager.newInstance(this);
    105         }
    106 
    107         initializeLocalProfile();
    108     }
    109 
    110     /**
    111      * Logs you into your SIP provider, registering this device as the location to
    112      * send SIP calls to for your SIP address.
    113      */
    114     public void initializeLocalProfile() {
    115         if (manager == null) {
    116             return;
    117         }
    118 
    119         if (me != null) {
    120             closeLocalProfile();
    121         }
    122 
    123         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
    124         String username = prefs.getString("namePref", "");
    125         String domain = prefs.getString("domainPref", "");
    126         String password = prefs.getString("passPref", "");
    127 
    128         if (username.length() == 0 || domain.length() == 0 || password.length() == 0) {
    129             showDialog(UPDATE_SETTINGS_DIALOG);
    130             return;
    131         }
    132 
    133         try {
    134             SipProfile.Builder builder = new SipProfile.Builder(username, domain);
    135             builder.setPassword(password);
    136             me = builder.build();
    137 
    138             Intent i = new Intent();
    139             i.setAction("android.SipDemo.INCOMING_CALL");
    140             PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
    141             manager.open(me, pi, null);
    142 
    143 
    144             // This listener must be added AFTER manager.open is called,
    145             // Otherwise the methods aren't guaranteed to fire.
    146 
    147             manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
    148                     public void onRegistering(String localProfileUri) {
    149                         updateStatus("Registering with SIP Server...");
    150                     }
    151 
    152                     public void onRegistrationDone(String localProfileUri, long expiryTime) {
    153                         updateStatus("Ready");
    154                     }
    155 
    156                     public void onRegistrationFailed(String localProfileUri, int errorCode,
    157                             String errorMessage) {
    158                         updateStatus("Registration failed.  Please check settings.");
    159                     }
    160                 });
    161         } catch (ParseException pe) {
    162             updateStatus("Connection Error.");
    163         } catch (SipException se) {
    164             updateStatus("Connection error.");
    165         }
    166     }
    167 
    168     /**
    169      * Closes out your local profile, freeing associated objects into memory
    170      * and unregistering your device from the server.
    171      */
    172     public void closeLocalProfile() {
    173         if (manager == null) {
    174             return;
    175         }
    176         try {
    177             if (me != null) {
    178                 manager.close(me.getUriString());
    179             }
    180         } catch (Exception ee) {
    181             Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
    182         }
    183     }
    184 
    185     /**
    186      * Make an outgoing call.
    187      */
    188     public void initiateCall() {
    189 
    190         updateStatus(sipAddress);
    191 
    192         try {
    193             SipAudioCall.Listener listener = new SipAudioCall.Listener() {
    194                 // Much of the client's interaction with the SIP Stack will
    195                 // happen via listeners.  Even making an outgoing call, don't
    196                 // forget to set up a listener to set things up once the call is established.
    197                 @Override
    198                 public void onCallEstablished(SipAudioCall call) {
    199                     call.startAudio();
    200                     call.setSpeakerMode(true);
    201                     call.toggleMute();
    202                     updateStatus(call);
    203                 }
    204 
    205                 @Override
    206                 public void onCallEnded(SipAudioCall call) {
    207                     updateStatus("Ready.");
    208                 }
    209             };
    210 
    211             call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);
    212 
    213         }
    214         catch (Exception e) {
    215             Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
    216             if (me != null) {
    217                 try {
    218                     manager.close(me.getUriString());
    219                 } catch (Exception ee) {
    220                     Log.i("WalkieTalkieActivity/InitiateCall",
    221                             "Error when trying to close manager.", ee);
    222                     ee.printStackTrace();
    223                 }
    224             }
    225             if (call != null) {
    226                 call.close();
    227             }
    228         }
    229     }
    230 
    231     /**
    232      * Updates the status box at the top of the UI with a messege of your choice.
    233      * @param status The String to display in the status box.
    234      */
    235     public void updateStatus(final String status) {
    236         // Be a good citizen.  Make sure UI changes fire on the UI thread.
    237         this.runOnUiThread(new Runnable() {
    238             public void run() {
    239                 TextView labelView = (TextView) findViewById(R.id.sipLabel);
    240                 labelView.setText(status);
    241             }
    242         });
    243     }
    244 
    245     /**
    246      * Updates the status box with the SIP address of the current call.
    247      * @param call The current, active call.
    248      */
    249     public void updateStatus(SipAudioCall call) {
    250         String useName = call.getPeerProfile().getDisplayName();
    251         if(useName == null) {
    252           useName = call.getPeerProfile().getUserName();
    253         }
    254         updateStatus(useName + "@" + call.getPeerProfile().getSipDomain());
    255     }
    256 
    257     /**
    258      * Updates whether or not the user's voice is muted, depending on whether the button is pressed.
    259      * @param v The View where the touch event is being fired.
    260      * @param event The motion to act on.
    261      * @return boolean Returns false to indicate that the parent view should handle the touch event
    262      * as it normally would.
    263      */
    264     public boolean onTouch(View v, MotionEvent event) {
    265         if (call == null) {
    266             return false;
    267         } else if (event.getAction() == MotionEvent.ACTION_DOWN && call != null && call.isMuted()) {
    268             call.toggleMute();
    269         } else if (event.getAction() == MotionEvent.ACTION_UP && !call.isMuted()) {
    270             call.toggleMute();
    271         }
    272         return false;
    273     }
    274 
    275     public boolean onCreateOptionsMenu(Menu menu) {
    276         menu.add(0, CALL_ADDRESS, 0, "Call someone");
    277         menu.add(0, SET_AUTH_INFO, 0, "Edit your SIP Info.");
    278         menu.add(0, HANG_UP, 0, "End Current Call.");
    279 
    280         return true;
    281     }
    282 
    283     public boolean onOptionsItemSelected(MenuItem item) {
    284         switch (item.getItemId()) {
    285             case CALL_ADDRESS:
    286                 showDialog(CALL_ADDRESS);
    287                 break;
    288             case SET_AUTH_INFO:
    289                 updatePreferences();
    290                 break;
    291             case HANG_UP:
    292                 if(call != null) {
    293                     try {
    294                       call.endCall();
    295                     } catch (SipException se) {
    296                         Log.d("WalkieTalkieActivity/onOptionsItemSelected",
    297                                 "Error ending call.", se);
    298                     }
    299                     call.close();
    300                 }
    301                 break;
    302         }
    303         return true;
    304     }
    305 
    306     @Override
    307     protected Dialog onCreateDialog(int id) {
    308         switch (id) {
    309             case CALL_ADDRESS:
    310 
    311                 LayoutInflater factory = LayoutInflater.from(this);
    312                 final View textBoxView = factory.inflate(R.layout.call_address_dialog, null);
    313                 return new AlertDialog.Builder(this)
    314                         .setTitle("Call Someone.")
    315                         .setView(textBoxView)
    316                         .setPositiveButton(
    317                                 android.R.string.ok, new DialogInterface.OnClickListener() {
    318                                     public void onClick(DialogInterface dialog, int whichButton) {
    319                                         EditText textField = (EditText)
    320                                                 (textBoxView.findViewById(R.id.calladdress_edit));
    321                                         sipAddress = textField.getText().toString();
    322                                         initiateCall();
    323 
    324                                     }
    325                         })
    326                         .setNegativeButton(
    327                                 android.R.string.cancel, new DialogInterface.OnClickListener() {
    328                                     public void onClick(DialogInterface dialog, int whichButton) {
    329                                         // Noop.
    330                                     }
    331                         })
    332                         .create();
    333 
    334             case UPDATE_SETTINGS_DIALOG:
    335                 return new AlertDialog.Builder(this)
    336                         .setMessage("Please update your SIP Account Settings.")
    337                         .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    338                             public void onClick(DialogInterface dialog, int whichButton) {
    339                                 updatePreferences();
    340                             }
    341                         })
    342                         .setNegativeButton(
    343                                 android.R.string.cancel, new DialogInterface.OnClickListener() {
    344                                     public void onClick(DialogInterface dialog, int whichButton) {
    345                                         // Noop.
    346                                     }
    347                         })
    348                         .create();
    349         }
    350         return null;
    351     }
    352 
    353     public void updatePreferences() {
    354         Intent settingsActivity = new Intent(getBaseContext(),
    355                 SipSettings.class);
    356         startActivity(settingsActivity);
    357     }
    358 }
    359