since this is a fun learning project, moved from java to kotlin for
more fun (or desperation)
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion = 25
|
compileSdkVersion = 25
|
||||||
@ -20,6 +21,9 @@ android {
|
|||||||
'proguard-rules.pro'
|
'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
}
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
path 'src/main/cpp/CMakeLists.txt'
|
path 'src/main/cpp/CMakeLists.txt'
|
||||||
@ -31,4 +35,8 @@ dependencies {
|
|||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
compile 'com.android.support:appcompat-v7:25.2.0'
|
compile 'com.android.support:appcompat-v7:25.2.0'
|
||||||
compile 'com.android.support.constraint:constraint-layout:1.0.1'
|
compile 'com.android.support.constraint:constraint-layout:1.0.1'
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -314,22 +314,7 @@ Java_com_tutpro_baresip_MainActivity_ua_1aor(JNIEnv *env, jobject thiz, jstring
|
|||||||
return (*env)->NewStringUTF(env, "");
|
return (*env)->NewStringUTF(env, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT void JNICALL /* currently not in use */
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1isregistered(JNIEnv *env, jobject thiz, jlong ua_ptr)
|
|
||||||
{
|
|
||||||
struct ua *ua = (struct ua *)ua_ptr;
|
|
||||||
bool result;
|
|
||||||
|
|
||||||
result = ua_isregistered(ua);
|
|
||||||
if (ua == NULL) {
|
|
||||||
LOGD("ua_ptr is null\n");
|
|
||||||
} else {
|
|
||||||
LOGD("ua_ptr is NOT null\n");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1current_1set(JNIEnv *env, jobject thiz,
|
Java_com_tutpro_baresip_MainActivity_ua_1current_1set(JNIEnv *env, jobject thiz,
|
||||||
jstring javaAoR)
|
jstring javaAoR)
|
||||||
{
|
{
|
||||||
@ -343,7 +328,7 @@ Java_com_tutpro_baresip_MainActivity_ua_1current_1set(JNIEnv *env, jobject thiz,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL /* currently not in use */
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1current(JNIEnv *env, jobject thiz)
|
Java_com_tutpro_baresip_MainActivity_ua_1current(JNIEnv *env, jobject thiz)
|
||||||
{
|
{
|
||||||
struct ua *current_ua = uag_current();
|
struct ua *current_ua = uag_current();
|
||||||
@ -357,32 +342,18 @@ Java_com_tutpro_baresip_MainActivity_ua_1current(JNIEnv *env, jobject thiz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1prev_1call(JNIEnv *env, jobject thiz, jstring javaUA)
|
Java_com_tutpro_baresip_MainActivity_aor_1ua(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaAoR)
|
||||||
{
|
{
|
||||||
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
|
const char *native_aor = (*env)->GetStringUTFChars(env, javaAoR, 0);
|
||||||
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
|
struct ua *ua = uag_find_aor(native_aor);
|
||||||
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
|
char ua_buf[256];
|
||||||
|
|
||||||
struct call *call = ua_prev_call(ua);
|
if (ua == NULL)
|
||||||
char call_buf[256];
|
ua_buf[0] = '\0';
|
||||||
if (call == NULL)
|
|
||||||
call_buf[0] = '\0';
|
|
||||||
else
|
else
|
||||||
sprintf(call_buf, "%lu", (unsigned long)call);
|
sprintf(ua_buf, "%lu", (unsigned long)ua);
|
||||||
return (*env)->NewStringUTF(env, call_buf);
|
return (*env)->NewStringUTF(env, ua_buf);
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1call(JNIEnv *env, jobject thiz, jstring javaUA)
|
|
||||||
{
|
|
||||||
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
|
|
||||||
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
|
|
||||||
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
|
|
||||||
|
|
||||||
struct call *call = ua_call(ua);
|
|
||||||
char call_buf[256];
|
|
||||||
sprintf(call_buf, "%lu", (unsigned long)call);
|
|
||||||
return (*env)->NewStringUTF(env, call_buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
@ -398,28 +369,26 @@ Java_com_tutpro_baresip_MainActivity_call_1peeruri(JNIEnv *env, jobject thiz, js
|
|||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1connect(JNIEnv *env, jobject thiz,
|
Java_com_tutpro_baresip_MainActivity_ua_1connect(JNIEnv *env, jobject thiz,
|
||||||
jstring uri) {
|
jstring javaUA, jstring javaURI) {
|
||||||
struct call *call;
|
struct call *call;
|
||||||
struct ua *ua;
|
struct ua *ua;
|
||||||
int err;
|
int err;
|
||||||
const char *native_uri = (*env)->GetStringUTFChars(env, uri, 0);
|
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
|
||||||
|
const char *native_uri = (*env)->GetStringUTFChars(env, javaURI, 0);
|
||||||
char call_buf[256];
|
char call_buf[256];
|
||||||
|
|
||||||
LOGD("connecting to %s\n", native_uri);
|
LOGD("connecting ua %s to %s\n", native_ua, native_uri);
|
||||||
ua = uag_current();
|
ua = (struct ua *)strtoul(native_ua, NULL, 10);
|
||||||
if (ua != NULL) {
|
err = ua_connect(ua, &call, NULL, native_uri, NULL, VIDMODE_ON);
|
||||||
err = ua_connect(ua, &call, NULL, native_uri, NULL, VIDMODE_ON);
|
if (err) {
|
||||||
if (err) {
|
LOGW("connecting to %s failed with error %d\n", native_uri, err);
|
||||||
LOGW("connecting to %s failed with error %d\n", native_uri, err);
|
|
||||||
call_buf[0] = '\0';
|
|
||||||
} else {
|
|
||||||
sprintf(call_buf, "%lu", (unsigned long)call);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOGE("no current ua\n");
|
|
||||||
call_buf[0] = '\0';
|
call_buf[0] = '\0';
|
||||||
|
} else {
|
||||||
|
sprintf(call_buf, "%lu", (unsigned long)call);
|
||||||
}
|
}
|
||||||
(*env)->ReleaseStringUTFChars(env, uri, native_uri);
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaURI, native_uri);
|
||||||
return (*env)->NewStringUTF(env, call_buf);
|
return (*env)->NewStringUTF(env, call_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,7 +409,8 @@ Java_com_tutpro_baresip_MainActivity_ua_1answer(JNIEnv *env, jobject thiz,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_tutpro_baresip_MainActivity_call_1hold(JNIEnv *env, jobject thiz,
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_MainActivity_call_1hold(JNIEnv *env, jobject thiz,
|
||||||
jstring javaCall) {
|
jstring javaCall) {
|
||||||
const char *native_call = (*env)->GetStringUTFChars(env, javaCall, 0);
|
const char *native_call = (*env)->GetStringUTFChars(env, javaCall, 0);
|
||||||
LOGD("holding call %s\n", native_call);
|
LOGD("holding call %s\n", native_call);
|
||||||
@ -449,7 +419,8 @@ JNIEXPORT jint JNICALL Java_com_tutpro_baresip_MainActivity_call_1hold(JNIEnv *
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_tutpro_baresip_MainActivity_call_1unhold(JNIEnv *env, jobject thiz,
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_MainActivity_call_1unhold(JNIEnv *env, jobject thiz,
|
||||||
jstring javaCall) {
|
jstring javaCall) {
|
||||||
const char *native_call = (*env)->GetStringUTFChars(env, javaCall, 0);
|
const char *native_call = (*env)->GetStringUTFChars(env, javaCall, 0);
|
||||||
LOGD("holding call %s\n", native_call);
|
LOGD("holding call %s\n", native_call);
|
||||||
@ -477,7 +448,7 @@ Java_com_tutpro_baresip_MainActivity_ua_1hangup(JNIEnv *env, jobject thiz,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_tutpro_baresip_MainActivity_contacts_1remove(JNIEnv *env, jobject thiz) {
|
Java_com_tutpro_baresip_MainActivity_00024Companion_contacts_1remove(JNIEnv *env, jobject thiz) {
|
||||||
struct le *le;
|
struct le *le;
|
||||||
le = list_head(contact_list(baresip_contacts()));
|
le = list_head(contact_list(baresip_contacts()));
|
||||||
while ((le = list_head(contact_list(baresip_contacts())))) {
|
while ((le = list_head(contact_list(baresip_contacts())))) {
|
||||||
@ -488,8 +459,8 @@ Java_com_tutpro_baresip_MainActivity_contacts_1remove(JNIEnv *env, jobject thiz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_tutpro_baresip_MainActivity_contact_1add(JNIEnv *env, jobject thiz,
|
Java_com_tutpro_baresip_MainActivity_00024Companion_contact_1add(JNIEnv *env, jobject thiz,
|
||||||
jstring javaContact) {
|
jstring javaContact) {
|
||||||
struct pl pl_addr;
|
struct pl pl_addr;
|
||||||
const struct list *lst;
|
const struct list *lst;
|
||||||
struct le *le;
|
struct le *le;
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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; }
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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; }
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
31
app/src/main/kotlin/com/tutpro/baresip/AboutActivity.kt
Normal file
31
app/src/main/kotlin/com/tutpro/baresip/AboutActivity.kt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
class AboutActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_about)
|
||||||
|
val aboutView = findViewById(R.id.aboutText) as TextView
|
||||||
|
aboutView.isEnabled = false
|
||||||
|
aboutView.text = getString(R.string.aboutText)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
android.R.id.home -> {
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
10
app/src/main/kotlin/com/tutpro/baresip/Account.kt
Normal file
10
app/src/main/kotlin/com/tutpro/baresip/Account.kt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
class Account(val ua: String, val aoR: String, var status: String) {
|
||||||
|
private var statusImage: Int = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.statusImage = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
class AccountSpinnerAdapter(private val cxt: Context, private val aors: ArrayList<String>,
|
||||||
|
private val images: ArrayList<Int>) :
|
||||||
|
ArrayAdapter<Int>(cxt, android.R.layout.simple_spinner_item, images) {
|
||||||
|
|
||||||
|
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
return getImageForPosition(position, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
return getImageForPosition(position, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getImageForPosition(position: Int, parent: ViewGroup): View {
|
||||||
|
val inflater = cxt.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
val row = inflater.inflate(R.layout.account_spinner, parent, false)
|
||||||
|
val textView = row.findViewById(R.id.spinnerText) as TextView
|
||||||
|
textView.text = aors[position]
|
||||||
|
textView.textSize = 17f
|
||||||
|
val imageView = row.findViewById(R.id.spinnerImage) as ImageView
|
||||||
|
imageView.setImageResource(images[position])
|
||||||
|
return row
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
5
app/src/main/kotlin/com/tutpro/baresip/Call.kt
Normal file
5
app/src/main/kotlin/com/tutpro/baresip/Call.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
class Call(val ua: String, val call: String, val peerURI: String, var status: String) {
|
||||||
|
var hold: Boolean = false
|
||||||
|
}
|
||||||
3
app/src/main/kotlin/com/tutpro/baresip/Contact.kt
Normal file
3
app/src/main/kotlin/com/tutpro/baresip/Contact.kt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
class Contact(val name: String, val uri: String)
|
||||||
103
app/src/main/kotlin/com/tutpro/baresip/EditAccountsActivity.kt
Normal file
103
app/src/main/kotlin/com/tutpro/baresip/EditAccountsActivity.kt
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
class EditAccountsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private var editText: EditText? = null
|
||||||
|
private var path: String? = null
|
||||||
|
private var file: File? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_edit_accounts)
|
||||||
|
|
||||||
|
editText = findViewById(R.id.editAccounts) as EditText
|
||||||
|
path = applicationContext.filesDir.absolutePath + "/accounts"
|
||||||
|
file = File(path!!)
|
||||||
|
var content: String
|
||||||
|
|
||||||
|
if (!file!!.exists()) {
|
||||||
|
Log.e("Baresip", "Failed to find accounts file")
|
||||||
|
content = "No accounts"
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Found accounts file")
|
||||||
|
val length = file!!.length().toInt()
|
||||||
|
val bytes = ByteArray(length)
|
||||||
|
try {
|
||||||
|
val `in` = FileInputStream(file!!)
|
||||||
|
try {
|
||||||
|
`in`.read(bytes)
|
||||||
|
} finally {
|
||||||
|
`in`.close()
|
||||||
|
}
|
||||||
|
content = String(bytes)
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
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,
|
||||||
|
resources.getDimension(R.dimen.textsize))
|
||||||
|
editText!!.setText(content, TextView.BufferType.EDITABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
super.onCreateOptionsMenu(menu)
|
||||||
|
val inflater = menuInflater
|
||||||
|
inflater.inflate(R.menu.edit_menu, menu)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val i = Intent()
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.save -> {
|
||||||
|
try {
|
||||||
|
val fOut = FileOutputStream(file!!.absoluteFile, false)
|
||||||
|
val fWriter = OutputStreamWriter(fOut)
|
||||||
|
val res = editText!!.text.toString()
|
||||||
|
try {
|
||||||
|
fWriter.write(res)
|
||||||
|
fWriter.close()
|
||||||
|
fOut.close()
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
Log.e("Baresip", "Failed to write accounts file: " + e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: java.io.FileNotFoundException) {
|
||||||
|
Log.e("Baresip", "Failed to find accounts file: " + e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d("Baresip", "Updated accounts file")
|
||||||
|
setResult(RESULT_OK, i)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.cancel, android.R.id.home -> {
|
||||||
|
setResult(RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
103
app/src/main/kotlin/com/tutpro/baresip/EditConfigActivity.kt
Normal file
103
app/src/main/kotlin/com/tutpro/baresip/EditConfigActivity.kt
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
class EditConfigActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private var editText: EditText? = null
|
||||||
|
private var path: String? = null
|
||||||
|
private var file: File? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_edit_config)
|
||||||
|
|
||||||
|
editText = findViewById(R.id.editConfig) as EditText
|
||||||
|
path = applicationContext.filesDir.absolutePath + "/config"
|
||||||
|
// path = "/sdcard/baresip/config";
|
||||||
|
file = File(path!!)
|
||||||
|
var content: String
|
||||||
|
|
||||||
|
if (!file!!.exists()) {
|
||||||
|
Log.e("Baresip", "Failed to find config file")
|
||||||
|
content = "No config"
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Found config file")
|
||||||
|
val length = file!!.length().toInt()
|
||||||
|
val bytes = ByteArray(length)
|
||||||
|
try {
|
||||||
|
val `in` = FileInputStream(file!!)
|
||||||
|
try {
|
||||||
|
`in`.read(bytes)
|
||||||
|
} finally {
|
||||||
|
`in`.close()
|
||||||
|
}
|
||||||
|
content = String(bytes)
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
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,
|
||||||
|
resources.getDimension(R.dimen.textsize))
|
||||||
|
editText!!.setText(content, TextView.BufferType.EDITABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
super.onCreateOptionsMenu(menu)
|
||||||
|
val inflater = menuInflater
|
||||||
|
inflater.inflate(R.menu.edit_menu, menu)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val i = Intent(this, MainActivity::class.java)
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.save -> {
|
||||||
|
try {
|
||||||
|
val fOut = FileOutputStream(file!!.absoluteFile, false)
|
||||||
|
val fWriter = OutputStreamWriter(fOut)
|
||||||
|
val res = editText!!.text.toString()
|
||||||
|
try {
|
||||||
|
fWriter.write(res)
|
||||||
|
fWriter.close()
|
||||||
|
fOut.close()
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
Log.e("Baresip", "Failed to write config file: " + e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: java.io.FileNotFoundException) {
|
||||||
|
Log.e("Baresip", "Failed to find config file: " + e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d("Baresip", "Updated config file")
|
||||||
|
setResult(RESULT_OK, i)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.cancel, android.R.id.home -> {
|
||||||
|
setResult(RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
113
app/src/main/kotlin/com/tutpro/baresip/EditContactsActivity.kt
Normal file
113
app/src/main/kotlin/com/tutpro/baresip/EditContactsActivity.kt
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
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.MenuItem
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
class EditContactsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private var editText: EditText? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_edit_contacts)
|
||||||
|
editText = findViewById(R.id.editText) as EditText
|
||||||
|
val path = applicationContext.filesDir.absolutePath + "/contacts"
|
||||||
|
val file = File(path)
|
||||||
|
val content = Utils.getFileContents(file)
|
||||||
|
Log.d("Baresip", "Contacts length is: " + content.length)
|
||||||
|
editText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||||
|
resources.getDimension(R.dimen.textsize))
|
||||||
|
editText!!.setText(content, TextView.BufferType.EDITABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
super.onCreateOptionsMenu(menu)
|
||||||
|
val inflater = menuInflater
|
||||||
|
inflater.inflate(R.menu.edit_menu, menu)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val i = Intent(this, MainActivity::class.java)
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.save -> {
|
||||||
|
val path = applicationContext.filesDir.absolutePath + "/contacts"
|
||||||
|
val file = File(path)
|
||||||
|
Utils.putFileContents(file, editText!!.text.toString())
|
||||||
|
Log.d("Baresip", "Updated contacts file")
|
||||||
|
MainActivity.contacts_remove()
|
||||||
|
updateContactsAndNames(path)
|
||||||
|
// MainActivity.CalleeAdapter.notifyDataSetChanged(); does not work
|
||||||
|
setResult(RESULT_OK, i)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.cancel, android.R.id.home -> {
|
||||||
|
i.putExtra("action", "cancel")
|
||||||
|
setResult(RESULT_OK, i)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var Contacts: ArrayList<Contact> = java.util.ArrayList()
|
||||||
|
var Names: ArrayList<String> = java.util.ArrayList()
|
||||||
|
|
||||||
|
fun updateContactsAndNames(path: String) {
|
||||||
|
val file = File(path)
|
||||||
|
val lines = Utils.getFileContents(file).split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
var name: String
|
||||||
|
var uri: String
|
||||||
|
Contacts.clear()
|
||||||
|
Names.clear()
|
||||||
|
for (line in lines) {
|
||||||
|
line.trim { it <= ' ' }
|
||||||
|
if (line.startsWith("#") || line.length == 0) continue
|
||||||
|
val parts = line.split("\"".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
if (parts.size != 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 { it <= ' ' }
|
||||||
|
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(Contact(name, uri))
|
||||||
|
Names.add(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findContactURI(name: String): String {
|
||||||
|
for (c in Contacts) {
|
||||||
|
if (c.name == name) return c.uri
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
11
app/src/main/kotlin/com/tutpro/baresip/History.kt
Normal file
11
app/src/main/kotlin/com/tutpro/baresip/History.kt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import java.io.Serializable
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
|
||||||
|
class History(val ua: String, val call: String, val aor: String, val peerURI: String,
|
||||||
|
val direction: String, val connected: Boolean) : Serializable {
|
||||||
|
|
||||||
|
val time: GregorianCalendar = GregorianCalendar()
|
||||||
|
|
||||||
|
}
|
||||||
129
app/src/main/kotlin/com/tutpro/baresip/HistoryActivity.kt
Normal file
129
app/src/main/kotlin/com/tutpro/baresip/HistoryActivity.kt
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
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.widget.AdapterView
|
||||||
|
import android.widget.ListView
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
|
||||||
|
class HistoryActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
internal var uaHistory = ArrayList<HistoryRow>()
|
||||||
|
internal var posAtHistory = ArrayList<Int>()
|
||||||
|
internal var aor: String = ""
|
||||||
|
|
||||||
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_history)
|
||||||
|
|
||||||
|
val listview = findViewById(R.id.history) as ListView
|
||||||
|
|
||||||
|
val b = intent.extras
|
||||||
|
aor = b.getString("aor")
|
||||||
|
generate_ua_history(aor)
|
||||||
|
|
||||||
|
val adapter = HistoryListAdapter(this, uaHistory)
|
||||||
|
listview.adapter = adapter
|
||||||
|
listview.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
|
||||||
|
val row = uaHistory[position]
|
||||||
|
val i = Intent()
|
||||||
|
i.putExtra("peer_uri", row.peerURI)
|
||||||
|
setResult(Activity.RESULT_OK, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
listview.onItemLongClickListener = AdapterView.OnItemLongClickListener { _, _, pos, _ ->
|
||||||
|
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||||
|
when (which) {
|
||||||
|
DialogInterface.BUTTON_POSITIVE -> {
|
||||||
|
History.removeAt(posAtHistory[pos])
|
||||||
|
generate_ua_history(aor)
|
||||||
|
if (uaHistory.size == 0) {
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
DialogInterface.BUTTON_NEGATIVE -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val builder = AlertDialog.Builder(this@HistoryActivity,
|
||||||
|
R.style.Theme_AppCompat)
|
||||||
|
builder.setMessage("Do you want to delete " +
|
||||||
|
History[pos].peerURI + "?")
|
||||||
|
.setPositiveButton("Yes", dialogClickListener)
|
||||||
|
.setNegativeButton("No", dialogClickListener).show()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
listview.isLongClickable = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
android.R.id.home -> {
|
||||||
|
Log.d("Baresip", "Back array was pressed")
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generate_ua_history(aor: String) {
|
||||||
|
uaHistory.clear()
|
||||||
|
posAtHistory.clear()
|
||||||
|
for (i in History.indices.reversed()) {
|
||||||
|
val h = History[i]
|
||||||
|
if (h.aor == aor) {
|
||||||
|
val time: String
|
||||||
|
if (isToday(h.time)) {
|
||||||
|
val fmt = SimpleDateFormat("HH:mm")
|
||||||
|
time = fmt.format(h.time.time)
|
||||||
|
} else {
|
||||||
|
val fmt = SimpleDateFormat("MMM dd")
|
||||||
|
time = fmt.format(h.time.time)
|
||||||
|
}
|
||||||
|
if (h.direction == "in") {
|
||||||
|
if (h.connected) {
|
||||||
|
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_down_green, time))
|
||||||
|
} else {
|
||||||
|
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_down_red, time))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (h.connected) {
|
||||||
|
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_up_green, time))
|
||||||
|
} else {
|
||||||
|
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_up_red, time))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
posAtHistory.add(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isToday(time: GregorianCalendar): Boolean {
|
||||||
|
val now = 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var History: ArrayList<History> = ArrayList<History>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
app/src/main/kotlin/com/tutpro/baresip/HistoryListAdapter.kt
Normal file
29
app/src/main/kotlin/com/tutpro/baresip/HistoryListAdapter.kt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
class HistoryListAdapter(private val cxt: Context, private val rows: ArrayList<HistoryRow>) :
|
||||||
|
ArrayAdapter<HistoryRow>(cxt, R.layout.history_row, rows) {
|
||||||
|
|
||||||
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
val row = rows[position]
|
||||||
|
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
val rowView = inflater.inflate(R.layout.history_row, parent, false)
|
||||||
|
val directionView = rowView.findViewById(R.id.direction) as ImageView
|
||||||
|
directionView.setImageResource(row.direction)
|
||||||
|
val peerURIView = rowView.findViewById(R.id.peer_uri) as TextView
|
||||||
|
peerURIView.text = row.peerURI
|
||||||
|
val timeView = rowView.findViewById(R.id.time) as TextView
|
||||||
|
timeView.text = row.time
|
||||||
|
return rowView
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
3
app/src/main/kotlin/com/tutpro/baresip/HistoryRow.kt
Normal file
3
app/src/main/kotlin/com/tutpro/baresip/HistoryRow.kt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
class HistoryRow(val peerURI: String, val direction: Int, val time: String)
|
||||||
668
app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
Normal file
668
app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
Normal file
@ -0,0 +1,668 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
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 java.util.*
|
||||||
|
import java.io.*
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
mainActivityContext = applicationContext
|
||||||
|
layout = findViewById(R.id.mainActivityLayout) as RelativeLayout
|
||||||
|
callee = findViewById(R.id.callee) as AutoCompleteTextView
|
||||||
|
callButton = findViewById(R.id.callButton) as Button
|
||||||
|
holdButton = findViewById(R.id.holdButton) as Button
|
||||||
|
|
||||||
|
AoRSpinner = findViewById(R.id.AoRList) as Spinner
|
||||||
|
|
||||||
|
Log.i("Baresip", "Setting AccountAdapter")
|
||||||
|
AccountAdapter = AccountSpinnerAdapter(applicationContext, AoRs, Images)
|
||||||
|
AoRSpinner.adapter = AccountAdapter
|
||||||
|
AoRSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||||
|
val aor = AoRs[position]
|
||||||
|
val callee = findViewById(R.id.callee) as AutoCompleteTextView
|
||||||
|
val callButton = findViewById(R.id.callButton) as Button
|
||||||
|
val holdButton = findViewById(R.id.holdButton) as Button
|
||||||
|
Log.i("Baresip", "Setting $aor current")
|
||||||
|
val out = uaCalls(Out, aor_ua(aor))
|
||||||
|
if (out.size == 0) {
|
||||||
|
callee.text.clear()
|
||||||
|
callee.hint = "Callee"
|
||||||
|
callButton.text = "Call"
|
||||||
|
if (aorHasHistory(aor)) {
|
||||||
|
holdButton.text = "History"
|
||||||
|
holdButton.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
holdButton.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callee.setText(out[0].peerURI)
|
||||||
|
callButton.text = out[0].status
|
||||||
|
if (out[0].status == "Hangup") {
|
||||||
|
if (out[0].hold) {
|
||||||
|
holdButton.text = "Unhold"
|
||||||
|
} else {
|
||||||
|
holdButton.text = "Hold"
|
||||||
|
}
|
||||||
|
holdButton.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
holdButton.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val `in` = uaCalls(In, aor_ua(aor))
|
||||||
|
val view_count = layout.childCount
|
||||||
|
Log.d("Baresip", "View count is $view_count")
|
||||||
|
if (view_count > 5) {
|
||||||
|
layout.removeViews(5, view_count - 5)
|
||||||
|
}
|
||||||
|
for (c in `in`) {
|
||||||
|
for (call_index in In.indices) {
|
||||||
|
addCallViews(c, (call_index + 1) * 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||||
|
Log.i("Baresip", "Nothing selected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val assets = arrayOf("accounts", "contacts", "config", "busy.wav", "callwaiting.wav", "error.wav", "message.wav", "notfound.wav", "ring.wav", "ringback.wav")
|
||||||
|
val path = applicationContext.filesDir.path
|
||||||
|
Log.d("Baresip", "path is: $path")
|
||||||
|
var file = File(path)
|
||||||
|
if (!file.exists()) {
|
||||||
|
Log.d("Baresip", "Creating baresip directory")
|
||||||
|
try {
|
||||||
|
File(path).mkdirs()
|
||||||
|
} catch (e: Error) {
|
||||||
|
Log.e("Baresip", "Failed to create directory: " + e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for (a in assets) {
|
||||||
|
file = 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 = File(path, "history")
|
||||||
|
try {
|
||||||
|
val fis = FileInputStream(file)
|
||||||
|
val ois = ObjectInputStream(fis)
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
HistoryActivity.History = ois.readObject() as ArrayList<History>
|
||||||
|
Log.d("Baresip", "Restored History of " + HistoryActivity.History.size + " entries")
|
||||||
|
ois.close()
|
||||||
|
fis.close()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
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,
|
||||||
|
arrayOf(Manifest.permission.RECORD_AUDIO), RECORD_AUDIO_PERMISSION)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!running) {
|
||||||
|
Log.i("Baresip", "Starting Baresip with path $path")
|
||||||
|
Thread(Runnable { baresipStart(path) }).start()
|
||||||
|
running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
EditContactsActivity.updateContactsAndNames(applicationContext.filesDir.absolutePath + "/contacts")
|
||||||
|
CalleeAdapter = ArrayAdapter(this, android.R.layout.select_dialog_item, EditContactsActivity.Names)
|
||||||
|
callee.threshold = 2
|
||||||
|
callee.setAdapter<ArrayAdapter<String>>(CalleeAdapter)
|
||||||
|
|
||||||
|
callButton.text = "Call"
|
||||||
|
callButton.setOnClickListener {
|
||||||
|
Log.d("Baresip", "AoR at position is " + AoRs[AoRSpinner.selectedItemPosition])
|
||||||
|
val aor = AoRs[AoRSpinner.selectedItemPosition]
|
||||||
|
if (callButton.text.toString() == "Call") {
|
||||||
|
call(aor, (findViewById(R.id.callee) as EditText).text.toString())
|
||||||
|
} else {
|
||||||
|
Log.i("Baresip", "Canceling UA " + aor_ua(aor) + " call " +
|
||||||
|
Out[0].call + " to " +
|
||||||
|
(findViewById(R.id.callee) as EditText).text)
|
||||||
|
ua_hangup(aor_ua(aor), Out[0].call, 486, "Rejected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val holdButton = findViewById(R.id.holdButton) as Button
|
||||||
|
holdButton.setOnClickListener {
|
||||||
|
when (holdButton.text.toString()) {
|
||||||
|
"Hold" -> {
|
||||||
|
Log.i("Baresip", "Holding up " + (findViewById(R.id.callee) as EditText).text)
|
||||||
|
call_hold(Out[0].call)
|
||||||
|
Out[0].hold = true
|
||||||
|
holdButton.text = "Unhold"
|
||||||
|
}
|
||||||
|
"Unhold" -> {
|
||||||
|
Log.i("Baresip", "Unholding " + (findViewById(R.id.callee) as EditText).text)
|
||||||
|
call_unhold(Out[0].call)
|
||||||
|
Out[0].hold = false
|
||||||
|
holdButton.text = "Hold"
|
||||||
|
}
|
||||||
|
"History" -> {
|
||||||
|
val i = Intent(this@MainActivity, HistoryActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("aor", AoRs[AoRSpinner.selectedItemPosition])
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivityForResult(i, HISTORY_CODE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
|
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 fun onRequestPermissionsResult(requestCode: Int,
|
||||||
|
permissions: Array<String>, grantResults: IntArray) {
|
||||||
|
when (requestCode) {
|
||||||
|
RECORD_AUDIO_PERMISSION -> {
|
||||||
|
if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
Log.d("Baresip", "RECORD_AUDIO permission granted")
|
||||||
|
} else {
|
||||||
|
Log.d("Baresip", "RECORD_AUDIO permission NOT granted")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else -> Log.e("Baresip", "Unknown permissions request code: $requestCode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
super.onCreateOptionsMenu(menu)
|
||||||
|
val inflater = menuInflater
|
||||||
|
inflater.inflate(R.menu.main_menu, menu)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val i: Intent
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.accounts -> {
|
||||||
|
i = Intent(this, EditAccountsActivity::class.java)
|
||||||
|
startActivityForResult(i, EDIT_ACCOUNTS_CODE)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.contacts -> {
|
||||||
|
i = Intent(this, EditContactsActivity::class.java)
|
||||||
|
startActivityForResult(i, EDIT_CONTACTS_CODE)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.config -> {
|
||||||
|
i = Intent(this, EditConfigActivity::class.java)
|
||||||
|
startActivityForResult(i, EDIT_CONFIG_CODE)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.about -> {
|
||||||
|
i = Intent(this, AboutActivity::class.java)
|
||||||
|
startActivityForResult(i, ABOUT_CODE)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.quit -> {
|
||||||
|
if (running) {
|
||||||
|
Log.d("Baresip", "Stopping")
|
||||||
|
val path = applicationContext.filesDir.path
|
||||||
|
Log.d("Baresip", "Saving history to $path")
|
||||||
|
val file = File(path, "history")
|
||||||
|
try {
|
||||||
|
val fos = FileOutputStream(file)
|
||||||
|
val oos = ObjectOutputStream(fos)
|
||||||
|
oos.writeObject(HistoryActivity.History)
|
||||||
|
oos.close()
|
||||||
|
fos.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.w("Baresip", "OutputStream exception: " + e.toString())
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
baresipStop()
|
||||||
|
running = false
|
||||||
|
}
|
||||||
|
finish()
|
||||||
|
System.exit(0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == EDIT_ACCOUNTS_CODE) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val alertDialog = 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"
|
||||||
|
) { dialog, _ -> 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) {
|
||||||
|
if (data != null) {
|
||||||
|
(findViewById(R.id.callee) as EditText).setText(data.getStringExtra("peer_uri"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resultCode == RESULT_CANCELED) {
|
||||||
|
Log.d("Baresip", "History canceled")
|
||||||
|
if (!aorHasHistory(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||||
|
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requestCode == EDIT_CONTACTS_CODE || requestCode == ABOUT_CODE) {
|
||||||
|
Log.d("Baresip", "Back arrow or Cancel pressed at request: $requestCode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addAccount(ua: String) {
|
||||||
|
val aor = ua_aor(ua)
|
||||||
|
Log.d("Baresip", "Adding account $ua with AoR $aor")
|
||||||
|
Accounts.add(Account(ua, aor, ""))
|
||||||
|
AoRs.add(aor)
|
||||||
|
Images.add(R.drawable.yellow)
|
||||||
|
runOnUiThread { AccountAdapter.notifyDataSetChanged() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun call(aor: String, callee: String) {
|
||||||
|
if (callee.length == 0) return
|
||||||
|
var uri = EditContactsActivity.findContactURI(callee)
|
||||||
|
if (!uri.startsWith("sip:")) uri = "sip:$uri"
|
||||||
|
if (!uri.contains("@")) {
|
||||||
|
val host = aor.substring(aor.indexOf("@") + 1)
|
||||||
|
uri = "$uri@$host"
|
||||||
|
}
|
||||||
|
(findViewById(R.id.callee) as EditText).setText(uri)
|
||||||
|
val ua = aor_ua(aor)
|
||||||
|
Log.i("Baresip", "Calling $ua / $uri")
|
||||||
|
val call = ua_connect(ua, uri)
|
||||||
|
if (call != "") {
|
||||||
|
Log.i("Baresip", "Adding outgoing call $ua / $call / $uri")
|
||||||
|
Out.add(Call(ua, call, uri, "Cancel"))
|
||||||
|
(findViewById(R.id.callButton) as Button).text = "Cancel"
|
||||||
|
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copyAssetToFile(asset: String, path: String) {
|
||||||
|
try {
|
||||||
|
val assetManager = assets
|
||||||
|
val `is` = assetManager.open(asset)
|
||||||
|
val os = FileOutputStream(path)
|
||||||
|
val buffer = ByteArray(512)
|
||||||
|
var byteRead: Int = `is`.read(buffer)
|
||||||
|
while (byteRead != -1) {
|
||||||
|
os.write(buffer, 0, byteRead)
|
||||||
|
byteRead = `is`.read(buffer)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e("Baresip", "Failed to read asset " + asset + ": " +
|
||||||
|
e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addCallViews(call: Call, id: Int) {
|
||||||
|
Log.d("Baresip", "Creating new Incoming textview at $id")
|
||||||
|
|
||||||
|
val caller_heading = TextView(mainActivityContext)
|
||||||
|
|
||||||
|
caller_heading.text = "Incoming call from ..."
|
||||||
|
caller_heading.setTextColor(Color.BLACK)
|
||||||
|
caller_heading.textSize = 20f
|
||||||
|
caller_heading.setPadding(10, 20, 0, 0)
|
||||||
|
caller_heading.id = id
|
||||||
|
val heading_params = LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||||
|
LayoutParams.WRAP_CONTENT)
|
||||||
|
if (id == 10)
|
||||||
|
heading_params.addRule(RelativeLayout.BELOW, callButton.id)
|
||||||
|
else
|
||||||
|
heading_params.addRule(RelativeLayout.BELOW, id - 10 + 3)
|
||||||
|
caller_heading.layoutParams = heading_params
|
||||||
|
layout.addView(caller_heading)
|
||||||
|
|
||||||
|
val caller_uri = TextView(mainActivityContext)
|
||||||
|
caller_uri.text = In[In.size - 1].peerURI
|
||||||
|
caller_uri.setTextColor(Color.GREEN)
|
||||||
|
caller_uri.textSize = 20f
|
||||||
|
caller_uri.setPadding(10, 10, 0, 10)
|
||||||
|
Log.d("Baresip", "Creating new caller textview at " + (id + 1))
|
||||||
|
caller_uri.id = id + 1
|
||||||
|
val caller_uri_params = LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||||
|
LayoutParams.WRAP_CONTENT)
|
||||||
|
caller_uri_params.addRule(RelativeLayout.BELOW, id)
|
||||||
|
caller_uri.layoutParams = caller_uri_params
|
||||||
|
layout.addView(caller_uri)
|
||||||
|
|
||||||
|
val answer_button = Button(mainActivityContext)
|
||||||
|
answer_button.text = call.status
|
||||||
|
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.id = id + 2
|
||||||
|
answer_button.setOnClickListener { v ->
|
||||||
|
val call_ua = call.ua
|
||||||
|
val call_call = call.call
|
||||||
|
when ((v as Button).text.toString()) {
|
||||||
|
"Answer" -> {
|
||||||
|
Log.i("Baresip", "UA " + call_ua + " accepting incoming call " +
|
||||||
|
call_call)
|
||||||
|
ua_answer(call_ua, call_call)
|
||||||
|
val final_in_index = callIndex(In, call_ua, call_call)
|
||||||
|
if (final_in_index >= 0) {
|
||||||
|
Log.d("Baresip", "Updating Hangup and Hold")
|
||||||
|
In[final_in_index].status = "Hangup"
|
||||||
|
In[final_in_index].hold = false
|
||||||
|
runOnUiThread {
|
||||||
|
val answer_id = (final_in_index + 1) * 10 + 2
|
||||||
|
val answer_but = layout.findViewById(answer_id) as Button
|
||||||
|
answer_but.text = "Hangup"
|
||||||
|
val reject_button = layout.findViewById(answer_id + 1) as Button
|
||||||
|
reject_button.text = "Hold"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"Hangup" -> {
|
||||||
|
Log.i("Baresip", "UA " + call_ua + " hanging up call " +
|
||||||
|
call_call)
|
||||||
|
ua_hangup(call_ua, call_call, 200, "OK")
|
||||||
|
}
|
||||||
|
else -> Log.e("Baresip", "Invalid answer button text: " + v.text.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val answer_button_params = LayoutParams(200,
|
||||||
|
LayoutParams.WRAP_CONTENT)
|
||||||
|
answer_button_params.addRule(RelativeLayout.BELOW, id + 1)
|
||||||
|
answer_button_params.setMargins(3, 10, 0, 0)
|
||||||
|
answer_button.layoutParams = answer_button_params
|
||||||
|
layout.addView(answer_button)
|
||||||
|
|
||||||
|
val reject_button = Button(mainActivityContext)
|
||||||
|
if (call.status == "Answer") {
|
||||||
|
reject_button.text = "Reject"
|
||||||
|
} else {
|
||||||
|
if (call.hold) {
|
||||||
|
reject_button.text = "Unhold"
|
||||||
|
} else {
|
||||||
|
reject_button.text = "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.id = id + 3
|
||||||
|
reject_button.setOnClickListener { v ->
|
||||||
|
when ((v as Button).text.toString()) {
|
||||||
|
"Reject" -> {
|
||||||
|
Log.i("Baresip", "UA " + call.ua +
|
||||||
|
" rejecting incoming call " + call.call)
|
||||||
|
ua_hangup(call.ua, call.call, 486, "Rejected")
|
||||||
|
}
|
||||||
|
"Hold" -> {
|
||||||
|
call_hold(call.call)
|
||||||
|
v.text = "Unhold"
|
||||||
|
call.hold = true
|
||||||
|
}
|
||||||
|
"Unhold" -> {
|
||||||
|
call_unhold(call.call)
|
||||||
|
v.text = "Hold"
|
||||||
|
call.hold = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val reject_button_params = LayoutParams(200,
|
||||||
|
LayoutParams.WRAP_CONTENT)
|
||||||
|
reject_button_params.addRule(RelativeLayout.BELOW, id + 1)
|
||||||
|
reject_button_params.setMargins(225, 10, 0, 0)
|
||||||
|
reject_button.layoutParams = reject_button_params
|
||||||
|
layout.addView(reject_button)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun callIndex(calls: ArrayList<Call>, ua: String, call: String): Int {
|
||||||
|
for (i in calls.indices) {
|
||||||
|
if (calls[i].ua.equals(ua) && calls[i].call == call)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun uaCalls(calls: ArrayList<Call>, ua: String): ArrayList<Call> {
|
||||||
|
val result = ArrayList<Call>()
|
||||||
|
for (i in calls.indices) {
|
||||||
|
if (calls[i].ua == ua) result.add(calls[i])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun aorHasHistory(aor: String): Boolean {
|
||||||
|
for (h in HistoryActivity.History) {
|
||||||
|
if (h.aor == aor) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun callHasHistory(ua: String, call: String): Boolean {
|
||||||
|
for (h in HistoryActivity.History) {
|
||||||
|
if (h.ua == ua && h.call == call) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStatus(event: String, ua: String, call: String) {
|
||||||
|
val aor = ua_aor(ua)
|
||||||
|
var call_index: Int
|
||||||
|
|
||||||
|
Log.d("Baresip", "Handling event " + event + " for " + ua + "/" + call + "/" +
|
||||||
|
aor)
|
||||||
|
|
||||||
|
for (account_index in Accounts.indices) {
|
||||||
|
if (Accounts[account_index].aoR == aor) {
|
||||||
|
Log.d("Baresip", "Found AoR at index $account_index")
|
||||||
|
when (event) {
|
||||||
|
"registering", "unregistering" -> {
|
||||||
|
}
|
||||||
|
"registered" -> {
|
||||||
|
Log.d("Baresip", "Setting status to green")
|
||||||
|
Accounts[account_index].status = "OK"
|
||||||
|
AoRs[account_index] = aor
|
||||||
|
Images[account_index] = R.drawable.green
|
||||||
|
runOnUiThread { AccountAdapter.notifyDataSetChanged() }
|
||||||
|
}
|
||||||
|
"registering failed" -> {
|
||||||
|
Log.d("Baresip", "Setting status to red")
|
||||||
|
Accounts[account_index].status = "FAIL"
|
||||||
|
AoRs[account_index] = aor
|
||||||
|
Images[account_index] = R.drawable.red
|
||||||
|
runOnUiThread { AccountAdapter.notifyDataSetChanged() }
|
||||||
|
}
|
||||||
|
"call ringing" -> {
|
||||||
|
}
|
||||||
|
"call established" -> {
|
||||||
|
val out_index = callIndex(Out, ua, call)
|
||||||
|
if (out_index >= 0) {
|
||||||
|
Log.d("Baresip", "Outbound call " + call + " established")
|
||||||
|
Out[out_index].status = "Hangup"
|
||||||
|
Out[out_index].hold = false
|
||||||
|
runOnUiThread {
|
||||||
|
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||||
|
callButton.text = "Hangup"
|
||||||
|
holdButton.text = "Hold"
|
||||||
|
holdButton.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||||
|
"out", true))
|
||||||
|
} else {
|
||||||
|
Log.d("Baresip", "Inbound call " + call + " established")
|
||||||
|
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||||
|
"in", true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"call incoming" -> {
|
||||||
|
val peer_uri = call_peeruri(call)
|
||||||
|
Log.d("Baresip", "Incoming call " + ua + "/" + call + "/" +
|
||||||
|
peer_uri)
|
||||||
|
val new_call = Call(ua, call, peer_uri, "Answer")
|
||||||
|
In.add(new_call)
|
||||||
|
this@MainActivity.runOnUiThread {
|
||||||
|
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||||
|
addCallViews(new_call, In.size * 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"call closed" -> {
|
||||||
|
call_index = callIndex(In, ua, call)
|
||||||
|
if (call_index != -1) {
|
||||||
|
Log.d("Baresip", "Removing inbound call " + ua + "/" +
|
||||||
|
call + "/" + In[call_index].peerURI)
|
||||||
|
val view_id = (call_index + 1) * 10
|
||||||
|
val remove_count = In.size - call_index
|
||||||
|
In.removeAt(call_index)
|
||||||
|
this@MainActivity.runOnUiThread {
|
||||||
|
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||||
|
if (callButton.text == "Call") {
|
||||||
|
holdButton.text = "History"
|
||||||
|
holdButton.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
val caller_heading = layout.findViewById(view_id)
|
||||||
|
val view_index = layout.indexOfChild(caller_heading)
|
||||||
|
Log.d("Baresip", "Index of caller heading is $view_index")
|
||||||
|
layout.removeViews(view_index, 4 * remove_count)
|
||||||
|
for (i in call_index until In.size) {
|
||||||
|
this@MainActivity.addCallViews(In[i], (i + 1) * 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!callHasHistory(ua, call)) {
|
||||||
|
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||||
|
"in", false))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
call_index = callIndex(Out, ua, call)
|
||||||
|
if (call_index != -1) {
|
||||||
|
Log.d("Baresip", "Removing outgoing call " + ua + "/" +
|
||||||
|
call + "/" + Out[call_index].peerURI)
|
||||||
|
Out.removeAt(call_index)
|
||||||
|
runOnUiThread {
|
||||||
|
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||||
|
callButton.text = "Call"
|
||||||
|
callButton.isEnabled = true
|
||||||
|
callee.setText("")
|
||||||
|
callee.hint = "Callee"
|
||||||
|
holdButton.text = "History"
|
||||||
|
holdButton.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!callHasHistory(ua, call)) {
|
||||||
|
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||||
|
"out", false))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Unknown call " + ua + "/" + call +
|
||||||
|
" closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> Log.d("Baresip", "Unknown event '$event'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
external fun baresipStart(path: String)
|
||||||
|
external fun baresipStop()
|
||||||
|
external fun call_peeruri(call: String): String
|
||||||
|
external fun ua_aor(ua: String): String
|
||||||
|
external fun aor_ua(aor: String): String
|
||||||
|
external fun ua_connect(ua: String, peer_uri: String): String
|
||||||
|
external fun ua_answer(ua: String, call: String)
|
||||||
|
external fun call_hold(call: String): Int?
|
||||||
|
external fun call_unhold(call: String): Int?
|
||||||
|
external fun ua_hangup(ua: String, call: String, code: Int, reason: String)
|
||||||
|
external fun reload_config(): Int
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
internal lateinit var mainActivityContext: Context
|
||||||
|
internal lateinit var layout: RelativeLayout
|
||||||
|
internal lateinit var callee: AutoCompleteTextView
|
||||||
|
internal lateinit var callButton: Button
|
||||||
|
internal lateinit var holdButton: Button
|
||||||
|
internal lateinit var AccountAdapter: AccountSpinnerAdapter
|
||||||
|
internal lateinit var AoRSpinner: Spinner
|
||||||
|
|
||||||
|
internal var running: Boolean = false
|
||||||
|
internal var Accounts = ArrayList<Account>()
|
||||||
|
internal var AoRs = ArrayList<String>()
|
||||||
|
internal var Images = ArrayList<Int>()
|
||||||
|
internal var CalleeAdapter: ArrayAdapter<String>? = null
|
||||||
|
internal var In = ArrayList<Call>()
|
||||||
|
internal var Out = ArrayList<Call>()
|
||||||
|
|
||||||
|
private val RECORD_AUDIO_PERMISSION = 1
|
||||||
|
private val EDIT_ACCOUNTS_CODE = 1
|
||||||
|
private val EDIT_CONTACTS_CODE = 2
|
||||||
|
private val EDIT_CONFIG_CODE = 3
|
||||||
|
private val HISTORY_CODE = 4
|
||||||
|
private val ABOUT_CODE = 5
|
||||||
|
|
||||||
|
external fun contacts_remove()
|
||||||
|
external fun contact_add(contact: String)
|
||||||
|
|
||||||
|
init {
|
||||||
|
System.loadLibrary("baresip")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
67
app/src/main/kotlin/com/tutpro/baresip/Utils.kt
Normal file
67
app/src/main/kotlin/com/tutpro/baresip/Utils.kt
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
object Utils {
|
||||||
|
|
||||||
|
fun getFileContents(file: File): String {
|
||||||
|
if (!file.exists()) {
|
||||||
|
Log.e("Baresip", "Failed to find file: " + file.path)
|
||||||
|
return ""
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Found file: " + file.path)
|
||||||
|
val length = file.length().toInt()
|
||||||
|
val bytes = ByteArray(length)
|
||||||
|
try {
|
||||||
|
val `in` = FileInputStream(file)
|
||||||
|
try {
|
||||||
|
`in`.read(bytes)
|
||||||
|
} finally {
|
||||||
|
`in`.close()
|
||||||
|
}
|
||||||
|
return String(bytes)
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
Log.e("Baresip", "Failed to read file: " + file.path + ": " +
|
||||||
|
e.toString())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun putFileContents(file: File, contents: String) {
|
||||||
|
try {
|
||||||
|
val fOut = FileOutputStream(file.absoluteFile, false)
|
||||||
|
val fWriter = OutputStreamWriter(fOut)
|
||||||
|
try {
|
||||||
|
fWriter.write(contents)
|
||||||
|
fWriter.close()
|
||||||
|
fOut.close()
|
||||||
|
} catch (e: java.io.IOException) {
|
||||||
|
Log.e("Baresip", "Failed to put contents to file: " + e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: java.io.FileNotFoundException) {
|
||||||
|
Log.e("Baresip", "Failed to find contents file: " + e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun alertView(context: Context, message: String) {
|
||||||
|
val alertDialog = AlertDialog.Builder(context).create()
|
||||||
|
alertDialog.setTitle("Alert")
|
||||||
|
alertDialog.setMessage(message)
|
||||||
|
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK"
|
||||||
|
) { dialog, _ -> dialog.dismiss() }
|
||||||
|
alertDialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,11 +1,13 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.2.30'
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|||||||
Reference in New Issue
Block a user