Added SIP Demo to sample apps.
Change-Id: Id98b6e542e1be5b9822a696936e735406c08500f
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.example.android.sip;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.sip.*;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity.
|
||||
*/
|
||||
public class IncomingCallReceiver extends BroadcastReceiver {
|
||||
/**
|
||||
* Processes the incoming call, answers it, and hands it over to the
|
||||
* WalkieTalkieActivity.
|
||||
* @param context The context under which the receiver is running.
|
||||
* @param intent The intent being received.
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
SipAudioCall incomingCall = null;
|
||||
try {
|
||||
|
||||
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
|
||||
@Override
|
||||
public void onRinging(SipAudioCall call, SipProfile caller) {
|
||||
try {
|
||||
call.answerCall(30);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context;
|
||||
|
||||
incomingCall = wtActivity.manager.takeAudioCall(intent, listener);
|
||||
incomingCall.answerCall(30);
|
||||
incomingCall.startAudio();
|
||||
incomingCall.setSpeakerMode(true);
|
||||
if(incomingCall.isMuted()) {
|
||||
incomingCall.toggleMute();
|
||||
}
|
||||
|
||||
wtActivity.call = incomingCall;
|
||||
|
||||
wtActivity.updateStatus(incomingCall);
|
||||
|
||||
} catch (Exception e) {
|
||||
if (incomingCall != null) {
|
||||
incomingCall.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
34
samples/SipDemo/src/com/example/android/sip/SipSettings.java
Normal file
34
samples/SipDemo/src/com/example/android/sip/SipSettings.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.example.android.sip;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
|
||||
/**
|
||||
* Handles SIP authentication settings for the Walkie Talkie app.
|
||||
*/
|
||||
public class SipSettings extends PreferenceActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// Note that none of the preferences are actually defined here.
|
||||
// They're all in the XML file res/xml/preferences.xml.
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.example.android.sip;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.*;
|
||||
import android.net.sip.*;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
/**
|
||||
* Handles all calling, receiving calls, and UI interaction in the WalkieTalkie app.
|
||||
*/
|
||||
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
|
||||
|
||||
public String sipAddress = null;
|
||||
|
||||
public SipManager manager = null;
|
||||
public SipProfile me = null;
|
||||
public SipAudioCall call = null;
|
||||
public IncomingCallReceiver callReceiver;
|
||||
|
||||
private static final int CALL_ADDRESS = 1;
|
||||
private static final int SET_AUTH_INFO = 2;
|
||||
private static final int UPDATE_SETTINGS_DIALOG = 3;
|
||||
private static final int HANG_UP = 4;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.walkietalkie);
|
||||
|
||||
ToggleButton pushToTalkButton = (ToggleButton) findViewById(R.id.pushToTalk);
|
||||
pushToTalkButton.setOnTouchListener(this);
|
||||
|
||||
// Set up the intent filter. This will be used to fire an
|
||||
// IncomingCallReceiver when someone calls the SIP address used by this
|
||||
// application.
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("android.SipDemo.INCOMING_CALL");
|
||||
callReceiver = new IncomingCallReceiver();
|
||||
this.registerReceiver(callReceiver, filter);
|
||||
|
||||
// "Push to talk" can be a serious pain when the screen keeps turning off.
|
||||
// Let's prevent that.
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
initializeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
// When we get back from the preference setting Activity, assume
|
||||
// settings have changed, and re-login with new auth info.
|
||||
initializeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (call != null) {
|
||||
call.close();
|
||||
}
|
||||
|
||||
closeLocalProfile();
|
||||
|
||||
if (callReceiver != null) {
|
||||
this.unregisterReceiver(callReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
public void initializeManager() {
|
||||
if(manager == null) {
|
||||
manager = SipManager.newInstance(this);
|
||||
}
|
||||
|
||||
initializeLocalProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs you into your SIP provider, registering this device as the location to
|
||||
* send SIP calls to for your SIP address.
|
||||
*/
|
||||
public void initializeLocalProfile() {
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (me != null) {
|
||||
closeLocalProfile();
|
||||
}
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
||||
String username = prefs.getString("namePref", "");
|
||||
String domain = prefs.getString("domainPref", "");
|
||||
String password = prefs.getString("passPref", "");
|
||||
|
||||
if (username.length() == 0 || domain.length() == 0 || password.length() == 0) {
|
||||
showDialog(UPDATE_SETTINGS_DIALOG);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
|
||||
builder.setPassword(password);
|
||||
me = builder.build();
|
||||
|
||||
Intent i = new Intent();
|
||||
i.setAction("android.SipDemo.INCOMING_CALL");
|
||||
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
|
||||
manager.open(me, pi, null);
|
||||
|
||||
|
||||
// This listener must be added AFTER manager.open is called,
|
||||
// Otherwise the methods aren't guaranteed to fire.
|
||||
|
||||
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
|
||||
public void onRegistering(String localProfileUri) {
|
||||
updateStatus("Registering with SIP Server...");
|
||||
}
|
||||
|
||||
public void onRegistrationDone(String localProfileUri, long expiryTime) {
|
||||
updateStatus("Ready");
|
||||
}
|
||||
|
||||
public void onRegistrationFailed(String localProfileUri, int errorCode,
|
||||
String errorMessage) {
|
||||
updateStatus("Registration failed. Please check settings.");
|
||||
}
|
||||
});
|
||||
} catch (ParseException pe) {
|
||||
updateStatus("Connection Error.");
|
||||
} catch (SipException se) {
|
||||
updateStatus("Connection error.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes out your local profile, freeing associated objects into memory
|
||||
* and unregistering your device from the server.
|
||||
*/
|
||||
public void closeLocalProfile() {
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (me != null) {
|
||||
manager.close(me.getUriString());
|
||||
}
|
||||
} catch (Exception ee) {
|
||||
Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an outgoing call.
|
||||
*/
|
||||
public void initiateCall() {
|
||||
|
||||
updateStatus(sipAddress);
|
||||
|
||||
try {
|
||||
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
|
||||
// Much of the client's interaction with the SIP Stack will
|
||||
// happen via listeners. Even making an outgoing call, don't
|
||||
// forget to set up a listener to set things up once the call is established.
|
||||
@Override
|
||||
public void onCallEstablished(SipAudioCall call) {
|
||||
call.startAudio();
|
||||
call.setSpeakerMode(true);
|
||||
call.toggleMute();
|
||||
updateStatus(call);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallEnded(SipAudioCall call) {
|
||||
updateStatus("Ready.");
|
||||
}
|
||||
};
|
||||
|
||||
call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
|
||||
if (me != null) {
|
||||
try {
|
||||
manager.close(me.getUriString());
|
||||
} catch (Exception ee) {
|
||||
Log.i("WalkieTalkieActivity/InitiateCall",
|
||||
"Error when trying to close manager.", ee);
|
||||
ee.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (call != null) {
|
||||
call.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status box at the top of the UI with a messege of your choice.
|
||||
* @param status The String to display in the status box.
|
||||
*/
|
||||
public void updateStatus(final String status) {
|
||||
// Be a good citizen. Make sure UI changes fire on the UI thread.
|
||||
this.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
TextView labelView = (TextView) findViewById(R.id.sipLabel);
|
||||
labelView.setText(status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status box with the SIP address of the current call.
|
||||
* @param call The current, active call.
|
||||
*/
|
||||
public void updateStatus(SipAudioCall call) {
|
||||
String useName = call.getPeerProfile().getDisplayName();
|
||||
if(useName == null) {
|
||||
useName = call.getPeerProfile().getUserName();
|
||||
}
|
||||
updateStatus(useName + "@" + call.getPeerProfile().getSipDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates whether or not the user's voice is muted, depending on whether the button is pressed.
|
||||
* @param v The View where the touch event is being fired.
|
||||
* @param event The motion to act on.
|
||||
* @return boolean Returns false to indicate that the parent view should handle the touch event
|
||||
* as it normally would.
|
||||
*/
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (call == null) {
|
||||
return false;
|
||||
} else if (event.getAction() == MotionEvent.ACTION_DOWN && call != null && call.isMuted()) {
|
||||
call.toggleMute();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_UP && !call.isMuted()) {
|
||||
call.toggleMute();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, CALL_ADDRESS, 0, "Call someone");
|
||||
menu.add(0, SET_AUTH_INFO, 0, "Edit your SIP Info.");
|
||||
menu.add(0, HANG_UP, 0, "End Current Call.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case CALL_ADDRESS:
|
||||
showDialog(CALL_ADDRESS);
|
||||
break;
|
||||
case SET_AUTH_INFO:
|
||||
updatePreferences();
|
||||
break;
|
||||
case HANG_UP:
|
||||
if(call != null) {
|
||||
try {
|
||||
call.endCall();
|
||||
} catch (SipException se) {
|
||||
Log.d("WalkieTalkieActivity/onOptionsItemSelected",
|
||||
"Error ending call.", se);
|
||||
}
|
||||
call.close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case CALL_ADDRESS:
|
||||
|
||||
LayoutInflater factory = LayoutInflater.from(this);
|
||||
final View textBoxView = factory.inflate(R.layout.call_address_dialog, null);
|
||||
return new AlertDialog.Builder(this)
|
||||
.setTitle("Call Someone.")
|
||||
.setView(textBoxView)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
EditText textField = (EditText)
|
||||
(textBoxView.findViewById(R.id.calladdress_edit));
|
||||
sipAddress = textField.getText().toString();
|
||||
initiateCall();
|
||||
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Noop.
|
||||
}
|
||||
})
|
||||
.create();
|
||||
|
||||
case UPDATE_SETTINGS_DIALOG:
|
||||
return new AlertDialog.Builder(this)
|
||||
.setMessage("Please update your SIP Account Settings.")
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
updatePreferences();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Noop.
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updatePreferences() {
|
||||
Intent settingsActivity = new Intent(getBaseContext(),
|
||||
SipSettings.class);
|
||||
startActivity(settingsActivity);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user