since this is a fun learning project, moved from java to kotlin for

more fun (or desperation)
This commit is contained in:
Juha Heinanen
2018-03-17 11:18:44 +13:00
parent 2a3802a951
commit afb4635af7
31 changed files with 1352 additions and 1593 deletions

View File

@ -1,35 +0,0 @@
package com.tutpro.baresip;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;
public class AboutActivity extends AppCompatActivity {
private TextView aboutView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
aboutView = (TextView)findViewById(R.id.aboutText);
aboutView.setEnabled(false);
aboutView.setText(getString(R.string.aboutText));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent i = new Intent();
setResult(RESULT_CANCELED, i);
finish();
break;
}
return true;
}
}

View File

@ -1,34 +0,0 @@
package com.tutpro.baresip;
public class Account {
private String ua, aor, status;
private int status_image;
public Account(String ua, String aor) {
this.ua = ua;
this.aor = aor;
this.status = "";
this.status_image = 0;
}
public void setStatusImage(int status_image) {
this.status_image = status_image;
}
public int getStatusImage() {
return status_image;
}
public String getUA() {
return ua;
}
public String getAoR() {
return aor;
}
public void setStatus(String status) { this.status = status; }
public String getStatus() {
return status;
}
}

View File

@ -1,47 +0,0 @@
package com.tutpro.baresip;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class AccountSpinnerAdapter extends ArrayAdapter<Integer> {
private ArrayList<Integer> images;
private ArrayList<String> aors;
private Context context;
public AccountSpinnerAdapter(Context context, ArrayList<String> aors, ArrayList<Integer> images) {
super(context, android.R.layout.simple_spinner_item, images);
this.images = images;
this.aors = aors;
this.context = context;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getImageForPosition(position, convertView, parent);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getImageForPosition(position, convertView, parent);
}
private View getImageForPosition(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.account_spinner, parent, false);
TextView textView = (TextView) row.findViewById(R.id.spinnerText);
textView.setText(aors.get(position));
textView.setTextSize(17);
ImageView imageView = (ImageView) row.findViewById(R.id.spinnerImage);
imageView.setImageResource(images.get(position));
return row;
}
}

View File

@ -1,40 +0,0 @@
package com.tutpro.baresip;
public class Call {
private String ua, call, peer_uri, status;
Boolean hold;
public Call(String ua, String call, String peer_uri, String status) {
this.ua = ua;
this.call = call;
this.peer_uri = peer_uri;
this.status = status;
}
public String getUA() {
return ua;
}
public String getCall() {
return call;
}
public String getPeerURI() {
return peer_uri;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setHold(Boolean hold) {
this.hold = hold;
}
public Boolean getHold() {
return hold;
}
}

View File

@ -1,20 +0,0 @@
package com.tutpro.baresip;
public class Contact {
private String name, uri;
public Contact(String name, String uri) {
this.name = name;
this.uri = uri;
}
public String getName() {
return name;
}
public String getURI() {
return uri;
}
}

View File

@ -1,104 +0,0 @@
package com.tutpro.baresip;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.TextView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class EditAccountsActivity extends AppCompatActivity {
private EditText editText;
private String path;
private File file;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_accounts);
editText = (EditText)findViewById(R.id.editAccounts);
path = getApplicationContext().getFilesDir().getAbsolutePath() + "/accounts";
file = new File(path);
String content;
if (!file.exists()) {
Log.e("Baresip", "Failed to find accounts file");
content = "No accounts";
} else {
Log.e("Baresip", "Found accounts file");
int length = (int)file.length();
byte[] bytes = new byte[length];
try {
FileInputStream in = new FileInputStream(file);
try {
in.read(bytes);
} finally {
in.close();
}
content = new String(bytes);
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to read accounts file: " + e.toString());
content = "Failed to read account file";
}
}
Log.d("Baresip", "Content length is: " + content.length());
editText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.textsize));
editText.setText(content, TextView.BufferType.EDITABLE);
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.edit_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
Intent i = new Intent();
switch (item.getItemId()) {
case R.id.save:
try {
FileOutputStream fOut =
new FileOutputStream(file.getAbsoluteFile(), false);
OutputStreamWriter fWriter = new OutputStreamWriter(fOut);
String res = editText.getText().toString();
try {
fWriter.write(res);
fWriter.close();
fOut.close();
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to write accounts file: " +
e.toString());
}
} catch (java.io.FileNotFoundException e) {
Log.e("Baresip", "Failed to find accounts file: " +
e.toString());
}
Log.d("Baresip", "Updated accounts file");
setResult(RESULT_OK, i);
finish();
return true;
case R.id.cancel:
case android.R.id.home:
setResult(RESULT_CANCELED, i);
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -1,104 +0,0 @@
package com.tutpro.baresip;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.TextView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class EditConfigActivity extends AppCompatActivity {
private EditText editText;
private String path;
private File file;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_config);
editText = (EditText)findViewById(R.id.editConfig);
path = getApplicationContext().getFilesDir().getAbsolutePath() + "/config";
// path = "/sdcard/baresip/config";
file = new File(path);
String content;
if (!file.exists()) {
Log.e("Baresip", "Failed to find config file");
content = "No config";
} else {
Log.e("Baresip", "Found config file");
int length = (int)file.length();
byte[] bytes = new byte[length];
try {
FileInputStream in = new FileInputStream(file);
try {
in.read(bytes);
} finally {
in.close();
}
content = new String(bytes);
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to read config file: " + e.toString());
content = "Failed to read account file";
}
}
Log.d("Baresip", "Content length is: " + content.length());
editText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.textsize));
editText.setText(content, TextView.BufferType.EDITABLE);
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.edit_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
Intent i = new Intent(this, MainActivity.class);
switch (item.getItemId()) {
case R.id.save:
try {
FileOutputStream fOut =
new FileOutputStream(file.getAbsoluteFile(), false);
OutputStreamWriter fWriter = new OutputStreamWriter(fOut);
String res = editText.getText().toString();
try {
fWriter.write(res);
fWriter.close();
fOut.close();
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to write config file: " +
e.toString());
}
} catch (java.io.FileNotFoundException e) {
Log.e("Baresip", "Failed to find config file: " +
e.toString());
}
Log.d("Baresip", "Updated config file");
setResult(RESULT_OK, i);
finish();
return true;
case R.id.cancel:
case android.R.id.home:
setResult(RESULT_CANCELED, i);
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -1,117 +0,0 @@
package com.tutpro.baresip;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.TextView;
import java.io.File;
import java.util.ArrayList;
public class EditContactsActivity extends AppCompatActivity {
private EditText editText;
static public ArrayList<Contact> Contacts = new java.util.ArrayList<>();
static public ArrayList<String> Names = new java.util.ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_contacts);
editText = (EditText)findViewById(R.id.editText);
String path = getApplicationContext().getFilesDir().getAbsolutePath() + "/contacts";
File file = new File(path);
String content = Utils.getFileContents(file);
Log.d("Baresip", "Contacts length is: " + content.length());
editText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.textsize));
editText.setText(content, TextView.BufferType.EDITABLE);
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.edit_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
Intent i = new Intent(this, MainActivity.class);
switch (item.getItemId()) {
case R.id.save:
String path = getApplicationContext().getFilesDir().getAbsolutePath() + "/contacts";
File file = new File(path);
Utils.putFileContents(file, editText.getText().toString());
Log.d("Baresip", "Updated contacts file");
MainActivity.contacts_remove();
updateContactsAndNames();
// MainActivity.CalleeAdapter.notifyDataSetChanged();
MainActivity.CalleeAdapter = new ArrayAdapter<String>
(this,android.R.layout.select_dialog_item, Names);
MainActivity.callee.setThreshold(2);
MainActivity.callee.setAdapter(MainActivity.CalleeAdapter);
i.putExtra("action", "save");
setResult(RESULT_OK, i);
finish();
return true;
case R.id.cancel:
case android.R.id.home:
i.putExtra("action", "cancel");
setResult(RESULT_OK, i);
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
static public void updateContactsAndNames() {
String path = MainActivity.mainActivityContext.getFilesDir().getAbsolutePath() + "/contacts";
File file = new File(path);
String[] lines = Utils.getFileContents(file).split("\n");
String name, uri;
Contacts.clear();
Names.clear();
for (String line : lines) {
line.trim();
if (line.startsWith("#") || line.length() == 0) continue;
String[] parts = line.split("\"");
if (parts.length != 3) {
Log.e("Baresip", "Invalid contacts line: " + line);
continue;
}
name = parts[1];
if (name.length() < 2) {
Log.e("Baresip", "Too short contact display name: " + name);
continue;
}
uri = parts[2].trim();
if (!uri.startsWith("<") || !uri.contains(">")) {
Log.e("Baresip", "Invalid contact uri: " + uri);
continue;
}
MainActivity.contact_add("\"" + name + "\" " + uri);
if (uri.indexOf(";access") > 0) continue;
uri = uri.substring(1, uri.indexOf(">"));
Log.d("Baresip", "Adding contact name/uri: " + name + "/" + uri);
Contacts.add(new Contact(name, uri));
Names.add(name);
}
}
static public String findContactURI(String name) {
for (Contact c : Contacts) {
if (c.getName().equals(name)) return c.getURI();
}
return name;
}
}

View File

@ -1,32 +0,0 @@
package com.tutpro.baresip;
import java.io.Serializable;
import java.util.GregorianCalendar;
public class History implements Serializable {
private static final long serialVersionUID = -299482035708790407L;
private String ua, call, aor, peer_uri, direction;
private GregorianCalendar time;
private Boolean connected;
public History(String ua, String call, String aor, String peer_uri, String direction,
Boolean connected) {
this.ua = ua;
this.call = call;
this.aor = aor;
this.peer_uri = peer_uri;
this.direction = direction;
this.time = new GregorianCalendar();
this.connected = connected;
}
public String getUA() { return ua; }
public String getCall() { return call; }
public String getAoR() { return aor; }
public String getPeerURI() { return peer_uri; }
public String getDirection() { return direction; }
public GregorianCalendar getTime() { return time; }
public Boolean getConnected() { return connected; }
}

View File

@ -1,135 +0,0 @@
package com.tutpro.baresip;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class HistoryActivity extends AppCompatActivity {
ArrayList<HistoryRow> uaHistory = new ArrayList<>();
ArrayList<Integer> posAtHistory = new ArrayList<>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
final ListView listview = (ListView) findViewById(R.id.history);
generate_ua_history();
final HistoryListAdapter adapter = new HistoryListAdapter(this, uaHistory);
listview.setAdapter(adapter);
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
HistoryRow row = uaHistory.get(position);
Intent i = new Intent();
i.putExtra("peer_uri", row.getPeerURI());
setResult(RESULT_OK, i);
finish();
}
});
listview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int pos, long id) {
DialogInterface.OnClickListener dialogClickListener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
MainActivity.History.remove((posAtHistory.get(pos)).intValue());
generate_ua_history();
if (uaHistory.size() == 0) {
Intent i = new Intent();
setResult(RESULT_CANCELED, i);
finish();
}
adapter.notifyDataSetChanged();
break;
case DialogInterface.BUTTON_NEGATIVE:
break;
}
}
};
AlertDialog.Builder builder =
new AlertDialog.Builder(HistoryActivity.this,
R.style.Theme_AppCompat);
builder.setMessage("Do you want to delete " +
MainActivity.History.get(pos).getPeerURI() + "?")
.setPositiveButton("Yes", dialogClickListener)
.setNegativeButton("No", dialogClickListener).show();
return true;
}
});
listview.setLongClickable(true);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Log.d("Baresip", "Back array was pressed");
Intent i = new Intent();
setResult(RESULT_CANCELED, i);
finish();
break;
}
return true;
}
private void generate_ua_history() {
uaHistory.clear();
posAtHistory.clear();
for (Integer i = MainActivity.History.size() - 1; i >= 0; i--) {
History h = MainActivity.History.get(i);
if (h.getAoR().equals(MainActivity.ua_aor(MainActivity.ua_current()))) {
String time;
if (isToday(h.getTime())) {
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm");
time = fmt.format(h.getTime().getTime());
} else {
SimpleDateFormat fmt = new SimpleDateFormat("MMM dd");
time = fmt.format(h.getTime().getTime());
}
if (h.getDirection().equals("in")) {
if (h.getConnected()) {
uaHistory.add(new HistoryRow(h.getPeerURI(), R.drawable.arrow_down_green, time));
} else {
uaHistory.add(new HistoryRow(h.getPeerURI(), R.drawable.arrow_down_red, time));
}
} else {
if (h.getConnected()) {
uaHistory.add(new HistoryRow(h.getPeerURI(), R.drawable.arrow_up_green, time));
} else {
uaHistory.add(new HistoryRow(h.getPeerURI(), R.drawable.arrow_up_red, time));
}
}
posAtHistory.add(i);
}
}
}
private Boolean isToday(GregorianCalendar time) {
GregorianCalendar now = new GregorianCalendar();
return now.get(Calendar.YEAR) == time.get(Calendar.YEAR) &&
now.get(Calendar.MONTH) == time.get(Calendar.MONTH) &&
now.get(Calendar.DAY_OF_MONTH) == time.get(Calendar.DAY_OF_MONTH);
}
}

View File

@ -1,38 +0,0 @@
package com.tutpro.baresip;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class HistoryListAdapter extends ArrayAdapter<HistoryRow> {
private Context context;
private ArrayList<HistoryRow> rows;
public HistoryListAdapter(Context context, ArrayList<HistoryRow> rows) {
super(context, R.layout.history_row, rows);
this.context = context;
this.rows = rows;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
HistoryRow row = rows.get(position);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.history_row, parent, false);
ImageView directionView = (ImageView) rowView.findViewById(R.id.direction);
directionView.setImageResource(row.getDirection());
TextView peerURIView = (TextView) rowView.findViewById(R.id.peer_uri);
peerURIView.setText(row.getPeerURI());
TextView timeView = (TextView) rowView.findViewById(R.id.time);
timeView.setText(row.getTime());
return rowView;
}
}

View File

@ -1,19 +0,0 @@
package com.tutpro.baresip;
public class HistoryRow {
private String peer_uri;
private Integer direction;
private String time;
public HistoryRow(String peer_uri, Integer direction, String time) {
this.peer_uri = peer_uri;
this.direction = direction;
this.time = time;
}
public String getPeerURI() { return peer_uri; }
public Integer getDirection() { return direction; }
public String getTime() { return time; }
}

View File

@ -1,737 +0,0 @@
package com.tutpro.baresip;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.*;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.AutoCompleteTextView;
import android.view.*;
import android.util.Log;
import android.content.Context;
import java.util.*;
import java.io.*;
public class MainActivity extends AppCompatActivity {
static Context mainActivityContext;
static Boolean running = false;
static AutoCompleteTextView callee;
static RelativeLayout layout;
static Button callButton;
static Button holdButton;
static ArrayList<Account> Accounts = new ArrayList<>();
static ArrayList<String> AoRs = new ArrayList<>();
static ArrayList<Integer> Images = new ArrayList<>();
static AccountSpinnerAdapter AccountAdapter = null;
static ArrayAdapter<String> CalleeAdapter = null;
static ArrayList<Call> In = new ArrayList<>();
static ArrayList<Call> Out = new ArrayList<>();
static ArrayList<History> History = new ArrayList<>();
static String CurrentUA = null;
private static final int RECORD_AUDIO_PERMISSION = 1;
private static final int EDIT_ACCOUNTS_CODE = 1;
private static final int EDIT_CONTACTS_CODE = 2;
private static final int EDIT_CONFIG_CODE = 3;
private static final int HISTORY_CODE = 4;
private static final int ABOUT_CODE = 5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityContext = getApplicationContext();
Spinner AoRSpinner = (Spinner) findViewById(R.id.AoRList);
Log.i("Baresip", "Setting AccountAdapter");
AccountAdapter = new AccountSpinnerAdapter(getApplicationContext(), AoRs, Images);
AoRSpinner.setAdapter(AccountAdapter);
AoRSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String aor = AoRs.get(position);
Log.i("Baresip", "Setting " + aor + " current");
ua_current_set(aor);
CurrentUA = ua_current();
ArrayList<Call> out = uaCalls(Out, CurrentUA);
if (out.size() == 0) {
callee.setHint("Callee");
callButton.setText("Call");
if (aorHasHistory(History, aor)) {
holdButton.setText("History");
holdButton.setVisibility(View.VISIBLE);
} else {
holdButton.setVisibility(View.INVISIBLE);
}
} else {
callee.setText(out.get(0).getPeerURI());
callButton.setText(out.get(0).getStatus());
if (out.get(0).getStatus().equals("Hangup")) {
if (out.get(0).getHold()) {
holdButton.setText("Unhold");
} else {
holdButton.setText("Hold");
}
holdButton.setVisibility(View.VISIBLE);
} else {
holdButton.setVisibility(View.INVISIBLE);
}
}
ArrayList<Call> in = uaCalls(In, CurrentUA);
int view_count = layout.getChildCount();
Log.d("Baresip", "View count is " + view_count);
if (view_count > 5) {
layout.removeViews(5, view_count - 5);
}
for (Call c: in) {
for (int call_index = 0; call_index < In.size(); call_index++) {
addCallViews(c,(call_index + 1) * 10);
}
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Log.i("Baresip", "Nothing selected");
}
});
String[] assets = {"accounts", "contacts", "config", "busy.wav", "callwaiting.wav",
"error.wav", "message.wav", "notfound.wav", "ring.wav", "ringback.wav"};
final String path = mainActivityContext.getFilesDir().getPath();
Log.d("Baresip", "path is: " + path);
File file = new File(path);
if (!file.exists()) {
Log.d("Baresip", "Creating baresip directory");
try {
new File(path).mkdirs();
} catch (Error e) {
Log.e("Baresip", "Failed to create directory: " +
e.toString());
}
}
for (String a : assets) {
file = new File(path + "/" + a);
if (!file.exists()) {
Log.d("Baresip", "Copying asset " + a);
copyAssetToFile(a, path + "/" + a);
} else {
Log.d("Baresip", "Asset " + a + " already copied");
}
}
file = new File(path, "history");
try {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
History = (ArrayList<History>)ois.readObject();
Log.d("Baresip", "Restored History");
ois.close();
fis.close();
} catch (Exception e) {
Log.w("Baresip", "InputStream exception: - " + e.toString());
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
Log.d("Baresip", "Baresip does not have RECORD_AUDIO permission");
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO}, RECORD_AUDIO_PERMISSION);
}
if (!running) {
Log.i("Baresip", "Starting Baresip with path " + path);
new Thread(new Runnable() {
public void run() {
baresipStart(path);
}
}).start();
running = true;
}
layout = (RelativeLayout) findViewById(R.id.mainActivityLayout);
callee = (AutoCompleteTextView)findViewById(R.id.callee);
EditContactsActivity.updateContactsAndNames();
CalleeAdapter = new ArrayAdapter<String>
(this,android.R.layout.select_dialog_item, EditContactsActivity.Names);
callee.setThreshold(2);
callee.setAdapter(CalleeAdapter);
callButton = (Button)findViewById(R.id.callButton);
callButton.setText("Call");
callButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (callButton.getText().toString().equals("Call")) {
call(((EditText) findViewById(R.id.callee)).getText().toString());
} else {
Log.i("Baresip", "Canceling UA " + CurrentUA + " call " +
Out.get(0).getCall() + " to " +
((EditText) findViewById(R.id.callee)).getText());
ua_hangup(CurrentUA, Out.get(0).getCall(), 486, "Rejected");
}
}
});
holdButton = (Button)findViewById(R.id.holdButton);
if (aorHasHistory(History, ua_aor(ua_current()))) {
holdButton.setText("History");
} else {
holdButton.setVisibility(View.INVISIBLE);
}
holdButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (holdButton.getText().toString()) {
case "Hold":
Log.i("Baresip", "Holding up " +
((EditText) findViewById(R.id.callee)).getText());
call_hold(Out.get(0).getCall());
Out.get(0).setHold(true);
holdButton.setText("Unhold");
break;
case "Unhold":
Log.i("Baresip", "Unholding " +
((EditText) findViewById(R.id.callee)).getText());
call_unhold(Out.get(0).getCall());
Out.get(0).setHold(false);
holdButton.setText("Hold");
break;
case "History":
Intent i = new Intent(MainActivity.this, HistoryActivity.class);
startActivityForResult(i, HISTORY_CODE);
break;
}
}
});
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.d("Baresip", "Screen orientation change to landscape");
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Log.d("Baresip", "Screen orientation change to portrait");
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case RECORD_AUDIO_PERMISSION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d("Baresip", "RECORD_AUDIO permission granted");
} else {
Log.d("Baresip", "RECORD_AUDIO permission NOT granted");
}
return;
}
default:
Log.e("Baresip", "Unknown permissions request code: " + requestCode);
}
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
Intent i;
switch (item.getItemId()) {
case R.id.accounts:
i = new Intent(this, EditAccountsActivity.class);
startActivityForResult(i, EDIT_ACCOUNTS_CODE);
return true;
case R.id.contacts:
i = new Intent(this, EditContactsActivity.class);
startActivityForResult(i, EDIT_CONTACTS_CODE);
return true;
case R.id.config:
i = new Intent(this, EditConfigActivity.class);
startActivityForResult(i, EDIT_CONFIG_CODE);
return true;
case R.id.about:
i = new Intent(this, AboutActivity.class);
startActivityForResult(i, ABOUT_CODE);
return true;
case R.id.quit:
if (running) {
Log.d("Baresip", "Stopping");
final String path = mainActivityContext.getFilesDir().getPath();
File file = new File(path,"history");
try {
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(History);
oos.close();
fos.close();
} catch (IOException e) {
Log.w("Baresip", "OutputStream exception: " + e.toString());
e.printStackTrace();
}
History.clear();
Accounts.clear();
AoRs.clear();
Images.clear();
baresipStop();
running = false;
}
finish();
System.exit(0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == EDIT_ACCOUNTS_CODE) {
if(resultCode == RESULT_OK) {
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Alert");
alertDialog.setMessage("You need to restart baresip in order to activate saved accounts!");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
if (resultCode == RESULT_CANCELED) {
Log.d("Baresip", "Edit accounts canceled");
}
}
if (requestCode == EDIT_CONFIG_CODE) {
if(resultCode == RESULT_OK) {
Utils.alertView(this,
"You need to restart baresip in order to activate saved config!");
reload_config();
}
if (resultCode == RESULT_CANCELED) {
Log.d("Baresip", "Edit config canceled");
}
}
if (requestCode == HISTORY_CODE) {
if(resultCode == RESULT_OK) {
callee.setText(data.getStringExtra("peer_uri"));
}
if(resultCode == RESULT_CANCELED) {
Log.d("Baresip", "History canceled");
if (!aorHasHistory(History, ua_aor(ua_current()))) {
holdButton.setVisibility(View.INVISIBLE);
}
}
}
if ((requestCode == EDIT_CONTACTS_CODE) || (requestCode == ABOUT_CODE)) {
Log.d("Baresip", "Back arrow or Cancel pressed at request: " + requestCode);
}
}
public void addAccount(String ua) {
String aor = ua_aor(ua);
Log.d("Baresip", "Adding account " + ua + " with AoR " + aor);
Accounts.add(new Account(ua, aor));
AoRs.add(aor);
Images.add(R.drawable.yellow);
runOnUiThread(new Runnable() {
@Override
public void run() {
AccountAdapter.notifyDataSetChanged();
}
});
}
private void call(String callee) {
if (callee.length() == 0) return;
String uri = EditContactsActivity.findContactURI(callee);
if (!uri.startsWith("sip:")) uri = "sip:" + uri;
if (!uri.contains("@")) {
String aor = ua_aor(CurrentUA);
String host = aor.substring(aor.indexOf("@") + 1);
uri = uri + "@" + host;
}
((EditText) findViewById(R.id.callee)).setText(uri);
Log.i("Baresip", "Calling " + uri);
String call = ua_connect(uri);
if (!call.equals("")) {
Log.i("Baresip", "Adding outgoing call " + CurrentUA + "/" + call +
"/" + uri);
Out.add(new Call(CurrentUA, call, uri, "Cancel"));
// History.add(new History(ua_aor(CurrentUA), uri, "out"));
callButton.setText("Cancel");
holdButton.setVisibility(View.INVISIBLE);
}
}
private void copyAssetToFile(String asset, String path) {
try {
AssetManager assetManager = getAssets();
InputStream is = assetManager.open(asset);
OutputStream os = new FileOutputStream(path);
byte [] buffer = new byte[512];
int byteRead;
while ((byteRead = is.read(buffer)) != -1) {
os.write(buffer, 0, byteRead);
}
} catch (IOException e) {
Log.e("Baresip", "Failed to read asset " + asset + ": " +
e.toString());
}
}
private void addCallViews(final Call call, int id) {
Log.d("Baresip", "Creating new Incoming textview at " + id);
TextView caller_heading = new TextView(mainActivityContext);
caller_heading.setText("Incoming call from ...");
caller_heading.setTextColor(Color.BLACK);
caller_heading.setTextSize(20);
caller_heading.setPadding(10, 20, 0, 0);
caller_heading.setId(id);
LayoutParams heading_params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
if (id == 10)
heading_params.addRule(RelativeLayout.BELOW, callButton.getId());
else
heading_params.addRule(RelativeLayout.BELOW,id - 10 + 3);
caller_heading.setLayoutParams(heading_params);
layout.addView(caller_heading);
TextView caller_uri = new TextView(mainActivityContext);
caller_uri.setText(In.get(In.size() - 1).getPeerURI());
caller_uri.setTextColor(Color.GREEN);
caller_uri.setTextSize(20);
caller_uri.setPadding(10, 10, 0, 10);
Log.d("Baresip", "Creating new caller textview at " + (id + 1));
caller_uri.setId(id + 1);
LayoutParams caller_uri_params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
caller_uri_params.addRule(RelativeLayout.BELOW, id);
caller_uri.setLayoutParams(caller_uri_params);
layout.addView(caller_uri);
Button answer_button = new Button(mainActivityContext);
answer_button.setText(call.getStatus());
answer_button.setBackgroundResource(android.R.drawable.btn_default);
answer_button.setTextColor(Color.BLACK);
Log.d("Baresip", "Creating new answer button at " + (id + 2));
answer_button.setId(id + 2);
answer_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String call_ua = call.getUA();
String call_call = call.getCall();
switch (((Button)v).getText().toString()) {
case "Answer":
Log.i("Baresip", "UA " + call_ua + " accepting incoming call " +
call_call);
ua_answer(call_ua, call_call);
final int final_in_index = callIndex(In, call_ua, call_call);
if (final_in_index >= 0) {
Log.d("Baresip", "Updating Hangup and Hold");
In.get(final_in_index).setStatus("Hangup");
In.get(final_in_index).setHold(false);
runOnUiThread(new Runnable() {
@Override
public void run() {
final int answer_id = (final_in_index + 1) * 10 + 2;
Button answer_button = (Button)layout.findViewById(answer_id);
answer_button.setText("Hangup");
Button reject_button = (Button)layout.findViewById(answer_id + 1);
reject_button.setText("Hold");
}
});
}
break;
case "Hangup":
Log.i("Baresip", "UA " + call_ua + " hanging up call " +
call_call);
ua_hangup(call_ua, call_call,200, "OK");
break;
default:
Log.e("Baresip", "Invalid answer button text: " +
((Button)v).getText().toString());
break;
}
}
});
LayoutParams answer_button_params = new LayoutParams(200,
LayoutParams.WRAP_CONTENT);
answer_button_params.addRule(RelativeLayout.BELOW, id + 1);
answer_button_params.setMargins(3, 10, 0, 0);
answer_button.setLayoutParams(answer_button_params);
layout.addView(answer_button);
Button reject_button = new Button(mainActivityContext);
if (call.getStatus().equals("Answer")) {
reject_button.setText("Reject");
} else {
if (call.getHold()) {
reject_button.setText("Unhold");
} else {
reject_button.setText("Hold");
}
}
reject_button.setBackgroundResource(android.R.drawable.btn_default);
reject_button.setTextColor(Color.BLACK);
Log.d("Baresip", "Creating new reject button at " + (id + 3));
reject_button.setId(id + 3);
reject_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (((Button)v).getText().toString()) {
case "Reject":
Log.i("Baresip", "UA " + call.getUA() +
" rejecting incoming call " + call.getCall());
ua_hangup(call.getUA(), call.getCall(), 486, "Rejected");
break;
case "Hold":
call_hold(call.getCall());
((Button)v).setText("Unhold");
call.setHold(true);
break;
case "Unhold":
call_unhold(call.getCall());
((Button)v).setText("Hold");
call.setHold(false);
break;
}
}
});
LayoutParams reject_button_params = new LayoutParams(200,
LayoutParams.WRAP_CONTENT);
reject_button_params.addRule(RelativeLayout.BELOW, id + 1);
reject_button_params.setMargins(225, 10, 0, 0);
reject_button.setLayoutParams(reject_button_params);
layout.addView(reject_button);
}
private int callIndex(ArrayList<Call> calls, String ua, String call) {
for (int i = 0; i < calls.size(); i++) {
if (calls.get(i).getUA().equals(ua) && calls.get(i).getCall().equals(call))
return i;
}
return -1;
}
private ArrayList<Call> uaCalls(ArrayList<Call> calls, String ua) {
ArrayList<Call> result = new ArrayList<>();
for (int i = 0; i < calls.size(); i++) {
if (calls.get(i).getUA().equals(ua)) result.add(calls.get(i));
}
return result;
}
private Boolean aorHasHistory(ArrayList<History> history, String aor) {
for (History h : history) {
if (h.getAoR().equals(aor)) return true;
}
return false;
}
private Boolean callHasHistory(ArrayList<History> history, String ua, String call) {
for (History h : history) {
if (h.getUA().equals(ua) && h.getCall().equals(call)) return true;
}
return false;
}
private void updateStatus(String event, final String ua, final String call) {
String aor = ua_aor(ua);
int call_index;
Log.d("Baresip", "Handling event " + event + " for " + ua + "/" + call + "/" +
aor);
for (int account_index = 0; account_index < Accounts.size(); account_index++) {
if (Accounts.get(account_index).getAoR().equals(aor)) {
Log.d("Baresip", "Found AoR at index " + account_index);
switch (event) {
case "registering":
case "unregistering":
// Log.d("Baresip", "Setting status to yellow");
break;
case "registered":
Log.d("Baresip", "Setting status to green");
Accounts.get(account_index).setStatus("OK");
AoRs.set(account_index, aor);
Images.set(account_index, R.drawable.green);
runOnUiThread(new Runnable() {
@Override
public void run() {
AccountAdapter.notifyDataSetChanged();
}
});
break;
case "registering failed":
Log.d("Baresip", "Setting status to red");
Accounts.get(account_index).setStatus("FAIL");
AoRs.set(account_index, aor);
Images.set(account_index, R.drawable.red);
runOnUiThread(new Runnable() {
@Override
public void run() {
AccountAdapter.notifyDataSetChanged();
}
});
break;
case "call ringing":
break;
case "call established":
Log.d("Baresip", "Out call index is " + (Out.size() - 1));
int out_index = callIndex(Out, ua, call);
if (out_index >= 0) {
Log.d("Baresip", "Update Hangup and Hold");
Out.get(out_index).setStatus("Hangup");
Out.get(out_index).setHold(false);
if (ua.equals(CurrentUA)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
callButton.setText("Hangup");
holdButton.setText("Hold");
holdButton.setVisibility(View.VISIBLE);
}
});
}
History.add(new History(ua, call, aor, call_peeruri(call),
"out", true));
break;
} else {
History.add(new History(ua, call, aor, call_peeruri(call),
"in", true));
}
Log.e("Baresip", "Unknown call " + ua + "/" + call +
" established");
break;
case "call incoming":
final String peer_uri = call_peeruri(call);
Log.d("Baresip", "Incoming call " + ua + "/" + call + "/" +
peer_uri);
final Call new_call = new Call(ua, call, peer_uri, "Answer");
In.add(new_call);
// History.add(new History(aor, call_peeruri(call), "in"));
Log.d("Baresip", "Current UA is " + CurrentUA);
if (ua.equals(CurrentUA)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
addCallViews(new_call, In.size() * 10);
}
});
}
break;
case "call closed":
call_index = callIndex(In, ua, call);
Log.d("Baresip", "Incoming call index is " + call_index);
if (call_index != -1) {
Log.d("Baresip", "Removing inbound call " + ua + "/" +
call + "/" + In.get(call_index).getPeerURI());
final int view_id = (call_index + 1) * 10;
final int remove_count = In.size() - call_index;
final int final_call_index = call_index;
In.remove(call_index);
Log.d("Baresip", "Current UA is " + CurrentUA);
if (ua.equals(CurrentUA)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (callButton.getText().equals("Call")) {
holdButton.setText("History");
holdButton.setVisibility(View.VISIBLE);
}
View caller_heading = layout.findViewById(view_id);
int view_index = layout.indexOfChild(caller_heading);
Log.d("Baresip", "Index of caller heading is " +
view_index);
layout.removeViews(view_index, 4 * remove_count);
for (int i = final_call_index; i < In.size(); i++) {
addCallViews(In.get(i), (i + 1) * 10);
}
}
});
}
if (!callHasHistory(History, ua, call)) {
History.add(new History(ua, call, aor, call_peeruri(call),
"in", false));
}
break;
}
call_index = callIndex(Out, ua, call);
Log.d("Baresip", "Outgoing call index is " + call_index);
if (call_index != -1) {
Log.d("Baresip", "Removing outgoing call " + ua + "/" +
call + "/" + Out.get(call_index).getPeerURI());
Out.remove(call_index);
if (ua.equals(CurrentUA)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
callButton.setText("Call");
callButton.setEnabled(true);
callee.setText("");
callee.setHint("Callee");
holdButton.setText("History");
holdButton.setVisibility(View.VISIBLE);
}
});
}
if (!callHasHistory(History, ua, call)) {
History.add(new History(ua, call, aor, call_peeruri(call),
"out", false));
}
break;
}
Log.e("Baresip", "Unknown call " + ua + "/" + call +
" closed");
break;
default:
Log.d("Baresip", "Unknown event '" + event + "'");
break;
}
}
}
}
public native void baresipStart(String path);
public native void baresipStop();
public static native String ua_current();
public static native String ua_aor(String ua);
public native Boolean ua_isregistered(long ua_ptr);
public native String ua_call(String ua);
public native String call_peeruri(String call);
public static native void ua_current_set(String s);
public native String ua_connect(String s);
public native void ua_answer(String ua, String call);
public native Integer call_hold(String call);
public native Integer call_unhold(String call);
public native void ua_hangup(String ua, String call, int code, String reason);
static public native void contacts_remove();
static public native void contact_add(String contact);
static public native int reload_config();
static {
System.loadLibrary("baresip");
}
}

View File

@ -1,71 +0,0 @@
package com.tutpro.baresip;
import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class Utils {
static public String getFileContents(File file) {
if (!file.exists()) {
Log.e("Baresip", "Failed to find file: " + file.getPath());
return "";
} else {
Log.e("Baresip", "Found file: " + file.getPath());
int length = (int) file.length();
byte[] bytes = new byte[length];
try {
FileInputStream in = new FileInputStream(file);
try {
in.read(bytes);
} finally {
in.close();
}
return new String(bytes);
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to read file: " + file.getPath() + ": " +
e.toString());
return "";
}
}
}
static public void putFileContents(File file, String contents) {
try {
FileOutputStream fOut =
new FileOutputStream(file.getAbsoluteFile(), false);
OutputStreamWriter fWriter = new OutputStreamWriter(fOut);
try {
fWriter.write(contents);
fWriter.close();
fOut.close();
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to put contents to file: " +
e.toString());
}
} catch (java.io.FileNotFoundException e) {
Log.e("Baresip", "Failed to find contents file: " +
e.toString());
}
}
static public void alertView( Context context, String message ) {
AlertDialog alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle("Alert");
alertDialog.setMessage(message);
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
}