1
/* $Id: MainActivity.java 4734 2014-02-05 09:32:57Z nanang $ */
3
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
package org.pjsip.pjsua2.app;
21
import android.os.Bundle;
22
import android.os.Handler;
23
import android.os.Message;
24
import android.app.Activity;
25
import android.app.AlertDialog;
26
import android.content.DialogInterface;
27
import android.content.Intent;
28
import android.content.pm.ApplicationInfo;
29
import android.view.LayoutInflater;
30
import android.view.Menu;
31
import android.view.MenuItem;
32
import android.view.View;
33
import android.widget.AdapterView;
34
import android.widget.CheckBox;
35
import android.widget.EditText;
36
import android.widget.ListView;
37
import android.widget.SimpleAdapter;
38
import android.widget.TextView;
40
import java.util.ArrayList;
41
import java.util.HashMap;
44
import org.pjsip.pjsua2.*;
46
public class MainActivity extends Activity implements Handler.Callback, MyAppObserver {
47
public static MyApp app = null;
48
public static MyCall currentCall = null;
49
public static MyAccount account = null;
50
public static AccountConfig accCfg = null;
52
private ListView buddyListView;
53
private SimpleAdapter buddyListAdapter;
54
private int buddyListSelectedIdx = -1;
55
ArrayList<Map<String, String>> buddyList;
56
private String lastRegStatus = "";
58
private final Handler handler = new Handler(this);
59
public class MSG_TYPE {
60
public final static int INCOMING_CALL = 1;
61
public final static int CALL_STATE = 2;
62
public final static int REG_STATE = 3;
63
public final static int BUDDY_STATE = 4;
66
private HashMap<String, String> putData(String uri, String status) {
67
HashMap<String, String> item = new HashMap<String, String>();
69
item.put("status", status);
73
private void showCallActivity() {
74
Intent intent = new Intent(this, CallActivity.class);
75
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
76
startActivity(intent);
80
protected void onCreate(Bundle savedInstanceState) {
81
super.onCreate(savedInstanceState);
82
setContentView(R.layout.activity_main);
86
/* Wait for GDB to init */
87
if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
90
} catch (InterruptedException e) {}
93
app.init(this, getFilesDir().getAbsolutePath());
96
if (app.accList.size() == 0) {
97
accCfg = new AccountConfig();
98
accCfg.setIdUri("sip:localhost");
99
accCfg.getNatConfig().setIceEnabled(true);
100
account = app.addAcc(accCfg);
102
account = app.accList.get(0);
103
accCfg = account.cfg;
106
buddyList = new ArrayList<Map<String, String>>();
107
for (int i = 0; i < account.buddyList.size(); i++) {
108
buddyList.add(putData(account.buddyList.get(i).cfg.getUri(),
109
account.buddyList.get(i).getStatusText()));
112
String[] from = { "uri", "status" };
113
int[] to = { android.R.id.text1, android.R.id.text2 };
114
buddyListAdapter = new SimpleAdapter(this, buddyList, android.R.layout.simple_list_item_2, from, to);
116
buddyListView = (ListView) findViewById(R.id.listViewBuddy);;
117
buddyListView.setAdapter(buddyListAdapter);
118
buddyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
120
public void onItemClick(AdapterView<?> parent, final View view,
121
int position, long id)
123
view.setSelected(true);
124
buddyListSelectedIdx = position;
131
public boolean onCreateOptionsMenu(Menu menu) {
132
// Inflate the menu; this adds items to the action bar if it is present.
133
getMenuInflater().inflate(R.menu.main, menu);
138
public boolean onOptionsItemSelected(MenuItem item) {
139
switch (item.getItemId()) {
140
case R.id.action_acc_config:
144
case R.id.action_quit:
145
Message m = Message.obtain(handler, 0);
157
public boolean handleMessage(Message m) {
163
Runtime.getRuntime().gc();
164
android.os.Process.killProcess(android.os.Process.myPid());
166
} else if (m.what == MSG_TYPE.CALL_STATE) {
168
CallInfo ci = (CallInfo) m.obj;
170
/* Forward the message to CallActivity */
171
if (CallActivity.handler_ != null) {
172
Message m2 = Message.obtain(CallActivity.handler_, MSG_TYPE.CALL_STATE, ci);
176
if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
179
} else if (m.what == MSG_TYPE.BUDDY_STATE) {
181
MyBuddy buddy = (MyBuddy) m.obj;
182
int idx = account.buddyList.indexOf(buddy);
184
/* Update buddy status text, if buddy is valid and
185
* the buddy lists in account and UI are sync-ed.
187
if (idx >= 0 && account.buddyList.size() == buddyList.size()) {
188
buddyList.get(idx).put("status", buddy.getStatusText());
189
buddyListAdapter.notifyDataSetChanged();
190
// TODO: selection color/mark is gone after this,
191
// dont know how to return it back.
192
//buddyListView.setSelection(buddyListSelectedIdx);
193
//buddyListView.performItemClick(buddyListView, buddyListSelectedIdx,
194
// buddyListView.getItemIdAtPosition(buddyListSelectedIdx));
196
/* Return back Call activity */
197
notifyCallState(currentCall);
200
} else if (m.what == MSG_TYPE.REG_STATE) {
202
String msg_str = (String) m.obj;
203
lastRegStatus = msg_str;
205
} else if (m.what == MSG_TYPE.INCOMING_CALL) {
208
final MyCall call = (MyCall) m.obj;
209
CallOpParam prm = new CallOpParam();
211
/* Only one call at anytime */
212
if (currentCall != null) {
213
prm.setStatusCode(pjsip_status_code.PJSIP_SC_BUSY_HERE);
216
} catch (Exception e) {}
220
/* Answer with ringing */
221
prm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING);
224
} catch (Exception e) {}
231
/* Message not handled */
240
private void dlgAccountSetting() {
242
LayoutInflater li = LayoutInflater.from(this);
243
View view = li.inflate(R.layout.dlg_account_config, null);
245
if (!lastRegStatus.isEmpty()) {
246
TextView tvInfo = (TextView)view.findViewById(R.id.textViewInfo);
247
tvInfo.setText("Last status: " + lastRegStatus);
250
AlertDialog.Builder adb = new AlertDialog.Builder(this);
252
adb.setTitle("Account Settings");
254
final EditText etId = (EditText)view.findViewById(R.id.editTextId);
255
final EditText etReg = (EditText)view.findViewById(R.id.editTextRegistrar);
256
final EditText etProxy = (EditText)view.findViewById(R.id.editTextProxy);
257
final EditText etUser = (EditText)view.findViewById(R.id.editTextUsername);
258
final EditText etPass = (EditText)view.findViewById(R.id.editTextPassword);
260
etId. setText(accCfg.getIdUri());
261
etReg. setText(accCfg.getRegConfig().getRegistrarUri());
262
StringVector proxies = accCfg.getSipConfig().getProxies();
263
if (proxies.size() > 0)
264
etProxy.setText(proxies.get(0));
267
AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds();
268
if (creds.size() > 0) {
269
etUser. setText(creds.get(0).getUsername());
270
etPass. setText(creds.get(0).getData());
276
adb.setCancelable(false);
277
adb.setPositiveButton("OK",
278
new DialogInterface.OnClickListener() {
279
public void onClick(DialogInterface dialog,int id) {
280
String acc_id = etId.getText().toString();
281
String registrar = etReg.getText().toString();
282
String proxy = etProxy.getText().toString();
283
String username = etUser.getText().toString();
284
String password = etPass.getText().toString();
286
accCfg.setIdUri(acc_id);
287
accCfg.getRegConfig().setRegistrarUri(registrar);
288
AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds();
290
if (!username.isEmpty()) {
291
creds.add(new AuthCredInfo("Digest", "*", username, 0, password));
293
StringVector proxies = accCfg.getSipConfig().getProxies();
295
if (!proxy.isEmpty()) {
300
accCfg.getNatConfig().setIceEnabled(true);
305
account.modify(accCfg);
306
} catch (Exception e) {}
309
adb.setNegativeButton("Cancel",
310
new DialogInterface.OnClickListener() {
311
public void onClick(DialogInterface dialog,int id) {
316
AlertDialog ad = adb.create();
321
public void makeCall(View view) {
322
if (buddyListSelectedIdx == -1)
325
/* Only one call at anytime */
326
if (currentCall != null) {
330
HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx);
331
String buddy_uri = item.get("uri");
333
MyCall call = new MyCall(account, -1);
334
CallOpParam prm = new CallOpParam();
335
CallSetting opt = prm.getOpt();
336
opt.setAudioCount(1);
337
opt.setVideoCount(0);
340
call.makeCall(buddy_uri, prm);
341
} catch (Exception e) {
350
private void dlgAddEditBuddy(BuddyConfig initial) {
351
final BuddyConfig cfg = new BuddyConfig();
352
final BuddyConfig old_cfg = initial;
353
final boolean is_add = initial == null;
355
LayoutInflater li = LayoutInflater.from(this);
356
View view = li.inflate(R.layout.dlg_add_buddy, null);
358
AlertDialog.Builder adb = new AlertDialog.Builder(this);
361
final EditText etUri = (EditText)view.findViewById(R.id.editTextUri);
362
final CheckBox cbSubs = (CheckBox)view.findViewById(R.id.checkBoxSubscribe);
365
adb.setTitle("Add Buddy");
367
adb.setTitle("Edit Buddy");
368
etUri. setText(initial.getUri());
369
cbSubs.setChecked(initial.getSubscribe());
372
adb.setCancelable(false);
373
adb.setPositiveButton("OK",
374
new DialogInterface.OnClickListener() {
375
public void onClick(DialogInterface dialog,int id) {
376
cfg.setUri(etUri.getText().toString());
377
cfg.setSubscribe(cbSubs.isChecked());
380
account.addBuddy(cfg);
381
buddyList.add(putData(cfg.getUri(), ""));
382
buddyListAdapter.notifyDataSetChanged();
383
buddyListSelectedIdx = -1;
385
if (!old_cfg.getUri().equals(cfg.getUri())) {
386
account.delBuddy(buddyListSelectedIdx);
387
account.addBuddy(cfg);
388
buddyList.remove(buddyListSelectedIdx);
389
buddyList.add(putData(cfg.getUri(), ""));
390
buddyListAdapter.notifyDataSetChanged();
391
buddyListSelectedIdx = -1;
392
} else if (old_cfg.getSubscribe() != cfg.getSubscribe()) {
393
MyBuddy bud = account.buddyList.get(buddyListSelectedIdx);
395
bud.subscribePresence(cfg.getSubscribe());
396
} catch (Exception e) {}
401
adb.setNegativeButton("Cancel",
402
new DialogInterface.OnClickListener() {
403
public void onClick(DialogInterface dialog,int id) {
408
AlertDialog ad = adb.create();
412
public void addBuddy(View view) {
413
dlgAddEditBuddy(null);
416
public void editBuddy(View view) {
417
if (buddyListSelectedIdx == -1)
420
BuddyConfig old_cfg = account.buddyList.get(buddyListSelectedIdx).cfg;
421
dlgAddEditBuddy(old_cfg);
424
public void delBuddy(View view) {
425
if (buddyListSelectedIdx == -1)
428
final HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx);
429
String buddy_uri = item.get("uri");
431
DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() {
433
public void onClick(DialogInterface dialog, int which) {
435
case DialogInterface.BUTTON_POSITIVE:
436
account.delBuddy(buddyListSelectedIdx);
437
buddyList.remove(item);
438
buddyListAdapter.notifyDataSetChanged();
439
buddyListSelectedIdx = -1;
441
case DialogInterface.BUTTON_NEGATIVE:
447
AlertDialog.Builder adb = new AlertDialog.Builder(this);
448
adb.setTitle(buddy_uri);
449
adb.setMessage("\nDelete this buddy?\n");
450
adb.setPositiveButton("Yes", ocl);
451
adb.setNegativeButton("No", ocl);
457
* === MyAppObserver ===
459
* As we cannot do UI from worker thread, the callbacks mostly just send
460
* a message to UI/main thread.
463
public void notifyIncomingCall(MyCall call) {
464
Message m = Message.obtain(handler, MSG_TYPE.INCOMING_CALL, call);
468
public void notifyRegState(pjsip_status_code code, String reason, int expiration) {
471
msg_str += "Unregistration";
473
msg_str += "Registration";
475
if (code.swigValue()/100 == 2)
476
msg_str += " successful";
478
msg_str += " failed: " + reason;
480
Message m = Message.obtain(handler, MSG_TYPE.REG_STATE, msg_str);
484
public void notifyCallState(MyCall call) {
485
if (currentCall == null || call.getId() != currentCall.getId())
491
} catch (Exception e) {
494
Message m = Message.obtain(handler, MSG_TYPE.CALL_STATE, ci);
498
public void notifyBuddyState(MyBuddy buddy) {
499
Message m = Message.obtain(handler, MSG_TYPE.BUDDY_STATE, buddy);
503
/* === end of MyAppObserver ==== */