diff options
Diffstat (limited to 'pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java')
-rw-r--r-- | pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java new file mode 100644 index 00000000..34633f97 --- /dev/null +++ b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java @@ -0,0 +1,497 @@ +/* $Id$ */ +/* + * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package org.pjsip.pjsua2.app; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.pjsip.pjsua2.*; + +public class MainActivity extends Activity implements Handler.Callback, MyAppObserver { + public static MyApp app = null; + public static MyCall currentCall = null; + public static MyAccount account = null; + public static AccountConfig accCfg = null; + + private ListView buddyListView; + private SimpleAdapter buddyListAdapter; + private int buddyListSelectedIdx = -1; + ArrayList<Map<String, String>> buddyList; + private String lastRegStatus = ""; + + private final Handler handler = new Handler(this); + public class MSG_TYPE { + public final static int INCOMING_CALL = 1; + public final static int CALL_STATE = 2; + public final static int REG_STATE = 3; + public final static int BUDDY_STATE = 4; + } + + private HashMap<String, String> putData(String uri, String status) { + HashMap<String, String> item = new HashMap<String, String>(); + item.put("uri", uri); + item.put("status", status); + return item; + } + + private void showCallActivity() { + Intent intent = new Intent(this, CallActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + if (app == null) { + app = new MyApp(); + /* Wait for GDB to init */ + if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) {} + } + + app.init(this, getFilesDir().getAbsolutePath()); + } + + if (app.accList.size() == 0) { + accCfg = new AccountConfig(); + accCfg.setIdUri("sip:localhost"); + account = app.addAcc(accCfg); + } else { + account = app.accList.get(0); + accCfg = account.cfg; + } + + buddyList = new ArrayList<Map<String, String>>(); + for (int i = 0; i < account.buddyList.size(); i++) { + buddyList.add(putData(account.buddyList.get(i).cfg.getUri(), + account.buddyList.get(i).getStatusText())); + } + + String[] from = { "uri", "status" }; + int[] to = { android.R.id.text1, android.R.id.text2 }; + buddyListAdapter = new SimpleAdapter(this, buddyList, android.R.layout.simple_list_item_2, from, to); + + buddyListView = (ListView) findViewById(R.id.listViewBuddy);; + buddyListView.setAdapter(buddyListAdapter); + buddyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, final View view, + int position, long id) + { + view.setSelected(true); + buddyListSelectedIdx = position; + } + }); + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_acc_config: + dlgAccountSetting(); + break; + + case R.id.action_quit: + Message m = Message.obtain(handler, 0); + m.sendToTarget(); + break; + + default: + break; + } + + return true; + } + + @Override + public boolean handleMessage(Message m) { + + if (m.what == 0) { + + app.deinit(); + finish(); + Runtime.getRuntime().gc(); + android.os.Process.killProcess(android.os.Process.myPid()); + + } else if (m.what == MSG_TYPE.CALL_STATE) { + + CallInfo ci = (CallInfo) m.obj; + + /* Forward the message to CallActivity */ + if (CallActivity.handler_ != null) { + Message m2 = Message.obtain(CallActivity.handler_, MSG_TYPE.CALL_STATE, ci); + m2.sendToTarget(); + } + + if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) + currentCall = null; + + } else if (m.what == MSG_TYPE.BUDDY_STATE) { + + MyBuddy buddy = (MyBuddy) m.obj; + int idx = account.buddyList.indexOf(buddy); + if (idx >= 0) { + buddyList.get(idx).put("status", buddy.getStatusText()); + buddyListAdapter.notifyDataSetChanged(); + // TODO: selection color/mark is gone after this, + // dont know how to return it back. + //buddyListView.setSelection(buddyListSelectedIdx); + //buddyListView.performItemClick(buddyListView, buddyListSelectedIdx, + // buddyListView.getItemIdAtPosition(buddyListSelectedIdx)); + + /* Return back Call activity */ + notifyCallState(currentCall); + } + + } else if (m.what == MSG_TYPE.REG_STATE) { + + String msg_str = (String) m.obj; + lastRegStatus = msg_str; + + } else if (m.what == MSG_TYPE.INCOMING_CALL) { + + /* Incoming call */ + final MyCall call = (MyCall) m.obj; + CallOpParam prm = new CallOpParam(); + + /* Only one call at anytime */ + if (currentCall != null) { + prm.setStatusCode(pjsip_status_code.PJSIP_SC_BUSY_HERE); + try { + call.hangup(prm); + } catch (Exception e) {} + return true; + } + + /* Answer with ringing */ + prm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING); + try { + call.answer(prm); + } catch (Exception e) {} + + currentCall = call; + showCallActivity(); + + } else { + + /* Message not handled */ + return false; + + } + + return true; + } + + + private void dlgAccountSetting() { + + LayoutInflater li = LayoutInflater.from(this); + View view = li.inflate(R.layout.dlg_account_config, null); + + if (!lastRegStatus.isEmpty()) { + TextView tvInfo = (TextView)view.findViewById(R.id.textViewInfo); + tvInfo.setText("Last status: " + lastRegStatus); + } + + AlertDialog.Builder adb = new AlertDialog.Builder(this); + adb.setView(view); + adb.setTitle("Account Settings"); + + final EditText etId = (EditText)view.findViewById(R.id.editTextId); + final EditText etReg = (EditText)view.findViewById(R.id.editTextRegistrar); + final EditText etProxy = (EditText)view.findViewById(R.id.editTextProxy); + final EditText etUser = (EditText)view.findViewById(R.id.editTextUsername); + final EditText etPass = (EditText)view.findViewById(R.id.editTextPassword); + + etId. setText(accCfg.getIdUri()); + etReg. setText(accCfg.getRegConfig().getRegistrarUri()); + StringVector proxies = accCfg.getSipConfig().getProxies(); + if (proxies.size() > 0) + etProxy.setText(proxies.get(0)); + else + etProxy.setText(""); + AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds(); + if (creds.size() > 0) { + etUser. setText(creds.get(0).getUsername()); + etPass. setText(creds.get(0).getData()); + } else { + etUser. setText(""); + etPass. setText(""); + } + + adb.setCancelable(false); + adb.setPositiveButton("OK", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog,int id) { + String acc_id = etId.getText().toString(); + String registrar = etReg.getText().toString(); + String proxy = etProxy.getText().toString(); + String username = etUser.getText().toString(); + String password = etPass.getText().toString(); + + accCfg.setIdUri(acc_id); + accCfg.getRegConfig().setRegistrarUri(registrar); + AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds(); + creds.clear(); + if (!username.isEmpty()) { + creds.add(new AuthCredInfo("Digest", "*", username, 0, password)); + } + StringVector proxies = accCfg.getSipConfig().getProxies(); + proxies.clear(); + if (!proxy.isEmpty()) { + proxies.add(proxy); + } + + /* Finally */ + lastRegStatus = ""; + try { + account.modify(accCfg); + } catch (Exception e) {} + } + }); + adb.setNegativeButton("Cancel", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog,int id) { + dialog.cancel(); + } + }); + + AlertDialog ad = adb.create(); + ad.show(); + } + + + public void makeCall(View view) { + if (buddyListSelectedIdx == -1) + return; + + /* Only one call at anytime */ + if (currentCall != null) { + return; + } + + HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx); + String buddy_uri = item.get("uri"); + + MyCall call = new MyCall(account, -1); + CallOpParam prm = new CallOpParam(); + CallSetting opt = prm.getOpt(); + opt.setAudioCount(1); + opt.setVideoCount(0); + + try { + call.makeCall(buddy_uri, prm); + } catch (Exception e) { + currentCall = null; + return; + } + + currentCall = call; + showCallActivity(); + } + + private void dlgAddEditBuddy(BuddyConfig initial) { + final BuddyConfig cfg = new BuddyConfig(); + final BuddyConfig old_cfg = initial; + final boolean is_add = initial == null; + + LayoutInflater li = LayoutInflater.from(this); + View view = li.inflate(R.layout.dlg_add_buddy, null); + + AlertDialog.Builder adb = new AlertDialog.Builder(this); + adb.setView(view); + + final EditText etUri = (EditText)view.findViewById(R.id.editTextUri); + final CheckBox cbSubs = (CheckBox)view.findViewById(R.id.checkBoxSubscribe); + + if (is_add) { + adb.setTitle("Add Buddy"); + } else { + adb.setTitle("Edit Buddy"); + etUri. setText(initial.getUri()); + cbSubs.setChecked(initial.getSubscribe()); + } + + adb.setCancelable(false); + adb.setPositiveButton("OK", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog,int id) { + cfg.setUri(etUri.getText().toString()); + cfg.setSubscribe(cbSubs.isChecked()); + + if (is_add) { + account.addBuddy(cfg); + buddyList.add(putData(cfg.getUri(), "")); + buddyListAdapter.notifyDataSetChanged(); + buddyListSelectedIdx = -1; + } else { + if (!old_cfg.getUri().equals(cfg.getUri())) { + account.delBuddy(buddyListSelectedIdx); + account.addBuddy(cfg); + buddyList.remove(buddyListSelectedIdx); + buddyList.add(putData(cfg.getUri(), "")); + buddyListAdapter.notifyDataSetChanged(); + buddyListSelectedIdx = -1; + } else if (old_cfg.getSubscribe() != cfg.getSubscribe()) { + MyBuddy bud = account.buddyList.get(buddyListSelectedIdx); + try { + bud.subscribePresence(cfg.getSubscribe()); + } catch (Exception e) {} + } + } + } + }); + adb.setNegativeButton("Cancel", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog,int id) { + dialog.cancel(); + } + }); + + AlertDialog ad = adb.create(); + ad.show(); + } + + public void addBuddy(View view) { + dlgAddEditBuddy(null); + } + + public void editBuddy(View view) { + if (buddyListSelectedIdx == -1) + return; + + BuddyConfig old_cfg = account.buddyList.get(buddyListSelectedIdx).cfg; + dlgAddEditBuddy(old_cfg); + } + + public void delBuddy(View view) { + if (buddyListSelectedIdx == -1) + return; + + final HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx); + String buddy_uri = item.get("uri"); + + DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + account.delBuddy(buddyListSelectedIdx); + buddyList.remove(item); + buddyListAdapter.notifyDataSetChanged(); + buddyListSelectedIdx = -1; + break; + case DialogInterface.BUTTON_NEGATIVE: + break; + } + } + }; + + AlertDialog.Builder adb = new AlertDialog.Builder(this); + adb.setTitle(buddy_uri); + adb.setMessage("\nDelete this buddy?\n"); + adb.setPositiveButton("Yes", ocl); + adb.setNegativeButton("No", ocl); + adb.show(); + } + + + /* + * === MyAppObserver === + * + * As we cannot do UI from worker thread, the callbacks mostly just send + * a message to UI/main thread. + */ + + public void notifyIncomingCall(MyCall call) { + Message m = Message.obtain(handler, MSG_TYPE.INCOMING_CALL, call); + m.sendToTarget(); + } + + public void notifyRegState(pjsip_status_code code, String reason, int expiration) { + String msg_str = ""; + if (expiration == 0) + msg_str += "Unregistration"; + else + msg_str += "Registration"; + + if (code.swigValue()/100 == 2) + msg_str += " successful"; + else + msg_str += " failed: " + reason; + + Message m = Message.obtain(handler, MSG_TYPE.REG_STATE, msg_str); + m.sendToTarget(); + } + + public void notifyCallState(MyCall call) { + if (currentCall == null || call.getId() != currentCall.getId()) + return; + + CallInfo ci; + try { + ci = call.getInfo(); + } catch (Exception e) { + ci = null; + } + Message m = Message.obtain(handler, MSG_TYPE.CALL_STATE, ci); + m.sendToTarget(); + } + + public void notifyBuddyState(MyBuddy buddy) { + Message m = Message.obtain(handler, MSG_TYPE.BUDDY_STATE, buddy); + m.sendToTarget(); + } + + /* === end of MyAppObserver ==== */ + +} |