added graphical account configuration and many other improvements
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ dependencies {
|
|||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation 'com.android.support:appcompat-v7:25.2.0'
|
implementation 'com.android.support:appcompat-v7:25.2.0'
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.0.1'
|
implementation 'com.android.support.constraint:constraint-layout:1.0.1'
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|||||||
@@ -51,8 +51,18 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".EditAccountsActivity"
|
android:name=".AccountsActivity"
|
||||||
android:label="Edit Accounts"
|
android:label="Accounts"
|
||||||
|
android:parentActivityName=".MainActivity">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".AccountActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
|
android:label="Account"
|
||||||
android:parentActivityName=".MainActivity">
|
android:parentActivityName=".MainActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
|||||||
@@ -31,4 +31,3 @@
|
|||||||
# <sip:[email protected];auth_pass=secret;transport=tcp>
|
# <sip:[email protected];auth_pass=secret;transport=tcp>
|
||||||
# <sip:user@[2001:df8:0:16:216:6fff:fe91:614c]:5070;transport=tcp;auth_pass=secret>
|
# <sip:user@[2001:df8:0:16:216:6fff:fe91:614c]:5070;transport=tcp;auth_pass=secret>
|
||||||
#
|
#
|
||||||
<sip:[email protected]>;auth_user=foo;auth_pass=xxx;outbound="sip:192.168.43.98:5060;transport=tcp";ptime=20;audio_codecs=OPUS/48000/2,PCMU,PCMA;video_codecs="";regint=600;pubint=0;sipnat=outbound
|
|
||||||
|
|||||||
@@ -128,9 +128,9 @@ module ice.so
|
|||||||
#module natpmp.so
|
#module natpmp.so
|
||||||
|
|
||||||
# Media encryption modules
|
# Media encryption modules
|
||||||
#module srtp.so
|
module srtp.so
|
||||||
#module dtls_srtp.so
|
module dtls_srtp.so
|
||||||
#module zrtp.so
|
module zrtp.so
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|||||||
+374
-13
@@ -102,7 +102,12 @@ static void ua_event_handler(struct ua *ua, enum ua_event ev,
|
|||||||
re_snprintf(event_buf, sizeof event_buf, "%s", "call incoming");
|
re_snprintf(event_buf, sizeof event_buf, "%s", "call incoming");
|
||||||
break;
|
break;
|
||||||
case UA_EVENT_CALL_MENC:
|
case UA_EVENT_CALL_MENC:
|
||||||
re_snprintf(event_buf, sizeof event_buf, "%s", prm);
|
if (prm[0] == '1')
|
||||||
|
re_snprintf(event_buf, sizeof event_buf, "call verify,%s", prm+2);
|
||||||
|
else if (prm[0] == '2')
|
||||||
|
re_snprintf(event_buf, sizeof event_buf, "call verified,%s", prm+2);
|
||||||
|
else
|
||||||
|
re_snprintf(event_buf, sizeof event_buf, "%s", "unknown menc event");
|
||||||
break;
|
break;
|
||||||
case UA_EVENT_CALL_CLOSED:
|
case UA_EVENT_CALL_CLOSED:
|
||||||
re_snprintf(event_buf, sizeof event_buf, "%s", "call closed");
|
re_snprintf(event_buf, sizeof event_buf, "%s", "call closed");
|
||||||
@@ -317,26 +322,342 @@ Java_com_tutpro_baresip_MainActivity_baresipStop(JNIEnv *env, jobject thiz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1aor(JNIEnv *env, jobject thiz, jstring javaUA)
|
Java_com_tutpro_baresip_AccountKt_account_1display_1name(JNIEnv *env, jobject thiz, jstring javaAcc) {
|
||||||
{
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
|
|
||||||
|
|
||||||
if (strlen(native_ua) > 0)
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
return (*env)->NewStringUTF(env, ua_aor(ua));
|
if (acc) {
|
||||||
|
const char *dn = account_display_name(acc);
|
||||||
|
if (dn)
|
||||||
|
return (*env)->NewStringUTF(env, dn);
|
||||||
|
else
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
} else
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1set_1display_1name(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaAcc, jstring javaDn) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const char *dn = (*env)->GetStringUTFChars(env, javaDn, 0);\
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (strlen(dn) > 0)
|
||||||
|
res = account_set_display_name(acc, dn);
|
||||||
|
else
|
||||||
|
res = account_set_display_name(acc, NULL);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaDn, dn);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1aor(JNIEnv *env, jobject thiz, jstring javaAcc) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
if (acc)
|
||||||
|
return (*env)->NewStringUTF(env, account_aor(acc));
|
||||||
else
|
else
|
||||||
return (*env)->NewStringUTF(env, "");
|
return (*env)->NewStringUTF(env, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_com_tutpro_baresip_MainActivity_ua_1mediaenc(JNIEnv *env, jobject thiz, jstring javaUA)
|
Java_com_tutpro_baresip_AccountKt_account_1auth_1user(JNIEnv *env, jobject thiz, jstring javaAcc) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
|
||||||
|
if (acc) {
|
||||||
|
const char *au = account_auth_user(acc);
|
||||||
|
if (au)
|
||||||
|
return (*env)->NewStringUTF(env, au);
|
||||||
|
else
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
} else
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1set_1auth_1user(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaAcc, jstring javaUser) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const char *user = (*env)->GetStringUTFChars(env, javaUser, 0);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (strlen(user) > 0)
|
||||||
|
res = account_set_auth_user(acc, user);
|
||||||
|
else
|
||||||
|
res = account_set_auth_user(acc, NULL);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaUser, user);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1auth_1pass(JNIEnv *env, jobject thiz, jstring javaAcc) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
|
||||||
|
if (acc) {
|
||||||
|
const char *ap = account_auth_pass(acc);
|
||||||
|
if (ap)
|
||||||
|
return (*env)->NewStringUTF(env, ap);
|
||||||
|
else
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
} else
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1set_1auth_1pass(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaAcc, jstring javaPass) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const char *pass = (*env)->GetStringUTFChars(env, javaPass, 0);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (strlen(pass) > 0)
|
||||||
|
res = account_set_auth_pass(acc, pass);
|
||||||
|
else
|
||||||
|
res = account_set_auth_pass(acc, NULL);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaPass, pass);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1outbound(JNIEnv *env, jobject thiz, jstring javaAcc,
|
||||||
|
jint ix) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
|
||||||
|
const uint16_t native_ix = ix;
|
||||||
|
const char *outbound;
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
if (acc) {
|
||||||
|
outbound = account_outbound(acc, native_ix);
|
||||||
|
if (outbound)
|
||||||
|
return (*env)->NewStringUTF(env, outbound);
|
||||||
|
else
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
} else {
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT int JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1set_1outbound(JNIEnv *env, jobject thiz, jstring javaAcc,
|
||||||
|
jstring javaOb, jint javaIx) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const char *ob = (*env)->GetStringUTFChars(env, javaOb, 0);
|
||||||
|
const uint16_t ix = javaIx;
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (strlen(ob) > 0)
|
||||||
|
res = account_set_outbound(acc, ob, ix);
|
||||||
|
else
|
||||||
|
res = account_set_outbound(acc, NULL, ix);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaOb, ob);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1audio_1codec(JNIEnv *env, jobject thiz, jstring javaAcc,
|
||||||
|
jint ix) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const uint16_t native_ix = ix;
|
||||||
|
const struct list *codecl;
|
||||||
|
char codec_buf[32];
|
||||||
|
struct le *le;
|
||||||
|
|
||||||
|
if (acc) {
|
||||||
|
codecl = account_aucodecl(acc);
|
||||||
|
if (!list_isempty(codecl)) {
|
||||||
|
int i = -1;
|
||||||
|
for (le = list_head(codecl); le != NULL; le = le->next) {
|
||||||
|
i++;
|
||||||
|
if (i > ix) break;
|
||||||
|
if (i == ix) {
|
||||||
|
const struct aucodec *ac = le->data;
|
||||||
|
re_snprintf(codec_buf, sizeof codec_buf, "%s/%u/%u", ac->name, ac->srate, ac->ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == ix) {
|
||||||
|
return (*env)->NewStringUTF(env, codec_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1set_1audio_1codecs(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaAcc, jstring javaCodecs) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const char *codecs = (*env)->GetStringUTFChars(env, javaCodecs, 0);
|
||||||
|
|
||||||
|
LOGD("setting audio codecs '%s'\n", codecs);
|
||||||
|
int res = account_set_audio_codecs(acc, codecs);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaCodecs, codecs);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1regint(JNIEnv *env, jobject thiz, jstring javaAcc) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
if (acc)
|
||||||
|
return account_regint(acc);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1set_1regint(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaAcc, jint javaRegint) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const uint32_t regint = javaRegint;
|
||||||
|
|
||||||
|
return account_set_regint(acc, regint);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1mediaenc(JNIEnv *env, jobject thiz, jstring javaAcc)
|
||||||
|
{
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
if (acc) {
|
||||||
|
const char *mediaenc = account_mediaenc(acc);
|
||||||
|
if (mediaenc) return (*env)->NewStringUTF(env, mediaenc);
|
||||||
|
}
|
||||||
|
return (*env)->NewStringUTF(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_AccountKt_account_1set_1mediaenc(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaAcc, jstring javaMencid) {
|
||||||
|
const char *native_acc = (*env)->GetStringUTFChars(env, javaAcc, 0);
|
||||||
|
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaAcc, native_acc);
|
||||||
|
const char *mencid = (*env)->GetStringUTFChars(env, javaMencid, 0);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (strlen(mencid) > 0)
|
||||||
|
res = account_set_mediaenc(acc, mencid);
|
||||||
|
else
|
||||||
|
res = account_set_mediaenc(acc, NULL);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaMencid, mencid);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_UserAgent_00024Companion_ua_1alloc(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaSipUri) {
|
||||||
|
const char *sip_uri = (*env)->GetStringUTFChars(env, javaSipUri, 0);
|
||||||
|
struct ua *ua;
|
||||||
|
LOGD("allocating UA '%s'\n", sip_uri);
|
||||||
|
int res = ua_alloc(&ua, sip_uri);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaSipUri, sip_uri);
|
||||||
|
if (res == 0) {
|
||||||
|
char ua_buf[64];
|
||||||
|
UpdateContext *pctx = (UpdateContext*)(&g_ctx);
|
||||||
|
sprintf(ua_buf, "%lu", (unsigned long)ua);
|
||||||
|
jstring javaUA = (*env)->NewStringUTF(env, ua_buf);
|
||||||
|
LOGD("adding account %s/%s\n", ua_aor(ua), ua_buf);
|
||||||
|
jmethodID accountId = (*env)->GetMethodID(env, pctx->mainActivityClz, "addAccount",
|
||||||
|
"(Ljava/lang/String;)V");
|
||||||
|
(*env)->CallVoidMethod(env, pctx->mainActivityObj, accountId, javaUA);
|
||||||
|
(*env)->DeleteLocalRef(env, javaUA);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_UserAgent_00024Companion_ua_1register(JNIEnv *env, jobject thiz,
|
||||||
|
jstring javaUA)
|
||||||
{
|
{
|
||||||
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
|
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
|
||||||
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
|
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
|
||||||
struct account *acc = ua_account(ua);
|
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
|
||||||
char *mediaenc = account_mediaenc(acc);
|
return ua_register(ua);
|
||||||
if (mediaenc)
|
}
|
||||||
return (*env)->NewStringUTF(env, mediaenc);
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_tutpro_baresip_UserAgent_00024Companion_ua_1unregister(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);
|
||||||
|
ua_unregister(ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_tutpro_baresip_UserAgent_00024Companion_ua_1isregistered(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);
|
||||||
|
return ua_isregistered(ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_tutpro_baresip_UserAgent_00024Companion_ua_1destroy(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);
|
||||||
|
mem_deref(ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_UserAgentKt_ua_1account(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);
|
||||||
|
struct account *acc;
|
||||||
|
char acc_buf[256];
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
|
||||||
|
acc_buf[0] = '\0';
|
||||||
|
if (ua) {
|
||||||
|
acc = ua_account(ua);
|
||||||
|
if (acc) sprintf(acc_buf, "%lu", (unsigned long) acc);
|
||||||
|
}
|
||||||
|
return (*env)->NewStringUTF(env, acc_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_UserAgentKt_ua_1aor(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);
|
||||||
|
if (ua)
|
||||||
|
return (*env)->NewStringUTF(env, ua_aor(ua));
|
||||||
else
|
else
|
||||||
return (*env)->NewStringUTF(env, "");
|
return (*env)->NewStringUTF(env, "");
|
||||||
}
|
}
|
||||||
@@ -514,10 +835,50 @@ Java_com_tutpro_baresip_MainActivity_reload_1config(JNIEnv *env, jobject thiz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_com_tutpro_baresip_MainActivity_cmd_1exec(JNIEnv *env, jobject thiz, jstring javaCmd) {
|
Java_com_tutpro_baresip_Utils_cmd_1exec(JNIEnv *env, jobject thiz, jstring javaCmd) {
|
||||||
const char *native_cmd = (*env)->GetStringUTFChars(env, javaCmd, 0);
|
const char *native_cmd = (*env)->GetStringUTFChars(env, javaCmd, 0);
|
||||||
LOGD("processing command '%s'\n", native_cmd);
|
LOGD("processing command '%s'\n", native_cmd);
|
||||||
int res = cmd_process_long(baresip_commands(), native_cmd, strlen(native_cmd), &pf_null, NULL);
|
int res = cmd_process_long(baresip_commands(), native_cmd, strlen(native_cmd), &pf_null, NULL);
|
||||||
(*env)->ReleaseStringUTFChars(env, javaCmd, native_cmd);
|
(*env)->ReleaseStringUTFChars(env, javaCmd, native_cmd);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_tutpro_baresip_Utils_audio_1codecs(JNIEnv *env, jobject thiz)
|
||||||
|
{
|
||||||
|
struct list *aucodecl = baresip_aucodecl();
|
||||||
|
struct le *le;
|
||||||
|
char codec_buf[256];
|
||||||
|
char *start = &(codec_buf[0]);
|
||||||
|
unsigned int left = sizeof codec_buf;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
for (le = list_head(aucodecl); le != NULL; le = le->next) {
|
||||||
|
const struct aucodec *ac = le->data;
|
||||||
|
if (start == &(codec_buf[0]))
|
||||||
|
len = re_snprintf(start, left, "%s/%u/%u", ac->name, ac->srate, ac->ch);
|
||||||
|
else
|
||||||
|
len = re_snprintf(start, left, ",%s/%u/%u", ac->name, ac->srate, ac->ch);
|
||||||
|
if (len == -1) {
|
||||||
|
LOGE("failed to print codec to buffer\n");
|
||||||
|
codec_buf[0] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start = start + len;
|
||||||
|
left = left - len;
|
||||||
|
}
|
||||||
|
return (*env)->NewStringUTF(env, codec_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_tutpro_baresip_Utils_uri_1decode(JNIEnv *env, jobject thiz, jstring javaUri) {
|
||||||
|
const char *uri = (*env)->GetStringUTFChars(env, javaUri, 0);
|
||||||
|
struct pl pl;
|
||||||
|
struct uri uri2;
|
||||||
|
|
||||||
|
LOGD("decoding uri '%s'\n", uri);
|
||||||
|
pl_set_str(&pl, uri);
|
||||||
|
int res = uri_decode(&uri2, &pl);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaUri, uri);
|
||||||
|
return res == 0;
|
||||||
|
}
|
||||||
@@ -1,3 +1,128 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
class Account(val ua: String, val aoR: String, val mediaenc: String, var status: String) {}
|
class Account(val accp: String) {
|
||||||
|
|
||||||
|
var displayName = account_display_name(accp)
|
||||||
|
val aor = account_aor(accp)
|
||||||
|
var authUser = account_auth_user(accp)
|
||||||
|
var authPass = account_auth_pass(accp)
|
||||||
|
var outbound = ArrayList<String>()
|
||||||
|
var audioCodec = ArrayList<String>()
|
||||||
|
var regint = account_regint(accp)
|
||||||
|
var mediaenc = account_mediaenc(accp)
|
||||||
|
|
||||||
|
init {
|
||||||
|
var i = 0
|
||||||
|
while (true) {
|
||||||
|
val ob = account_outbound(accp, i)
|
||||||
|
if (ob != "") {
|
||||||
|
outbound.add(ob)
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = 0
|
||||||
|
while (true) {
|
||||||
|
val ac = account_audio_codec(accp, i)
|
||||||
|
if (ac != "") {
|
||||||
|
audioCodec.add(ac)
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun print() : String {
|
||||||
|
|
||||||
|
var res: String
|
||||||
|
|
||||||
|
if (displayName != "")
|
||||||
|
res = "\"${displayName}\" "
|
||||||
|
else
|
||||||
|
res = ""
|
||||||
|
|
||||||
|
res = res + "<${aor}>"
|
||||||
|
|
||||||
|
if (authUser != "") res = res + ";auth_user=\"${authUser}\""
|
||||||
|
|
||||||
|
if (authPass != "") res = res + ";auth_pass=\"${authPass}\""
|
||||||
|
|
||||||
|
if (outbound.size > 0) res = res + ";outbound=\"${outbound[0]}\""
|
||||||
|
if (outbound.size > 1) res = res + ";outbound2=\"${outbound[1]}\""
|
||||||
|
|
||||||
|
if (audioCodec.size > 0) {
|
||||||
|
var first = true
|
||||||
|
res = res + ";audio_codecs="
|
||||||
|
for (c in audioCodec)
|
||||||
|
if (first) {
|
||||||
|
res = res + c
|
||||||
|
first = false
|
||||||
|
} else {
|
||||||
|
res = res + ",$c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaenc != "") res = res + ";mediaenc=${mediaenc}"
|
||||||
|
|
||||||
|
res = res + ";ptime=20;regint=${regint};regq=0.5;pubint=0;answermode=manual;sipnat=outbound"
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun accounts(): ArrayList<Account> {
|
||||||
|
var res = ArrayList<Account>()
|
||||||
|
for (ua in MainActivity.uas) {
|
||||||
|
res.add(ua.account)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fun find(uas: ArrayList<UserAgent>, accp: String): Account? {
|
||||||
|
for (ua in uas) {
|
||||||
|
if (ua.account.accp == accp) return ua.account
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findUA(aor: String): UserAgent? {
|
||||||
|
for (ua in MainActivity.uas) {
|
||||||
|
if (ua.aor == aor) return ua
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exists(uas: ArrayList<UserAgent>, aor: String): Boolean {
|
||||||
|
for (ua in uas) {
|
||||||
|
if (ua.account.aor == aor) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printNew(aor: String) : String {
|
||||||
|
var res = "<$aor>;auth_user=\"\";auth_pass=\"\";audio_codecs=opus/48000/2,PCMU,PCMA"
|
||||||
|
res = res + ";ptime=20;regint=600;regq=0.5;pubint=0;answermode=manual;sipnat=outbound"
|
||||||
|
res = res + ";mediaenc=zrtp"
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
external fun account_set_display_name(acc: String, dn: String): Int
|
||||||
|
external fun account_display_name(acc: String): String
|
||||||
|
external fun account_aor(acc: String): String
|
||||||
|
external fun account_auth_user(acc: String): String
|
||||||
|
external fun account_set_auth_user(acc: String, user: String): Int
|
||||||
|
external fun account_auth_pass(acc: String): String
|
||||||
|
external fun account_set_auth_pass(acc: String, pass: String): Int
|
||||||
|
external fun account_outbound(acc: String, ix: Int): String
|
||||||
|
external fun account_set_outbound(acc: String, ob: String, ix: Int): Int
|
||||||
|
external fun account_audio_codec(acc: String, ix: Int): String
|
||||||
|
external fun account_regint(acc: String): Int
|
||||||
|
external fun account_set_regint(acc: String, regint: Int): Int
|
||||||
|
external fun account_mediaenc(acc: String): String
|
||||||
|
external fun account_set_mediaenc(acc: String, mencid: String): Int
|
||||||
|
external fun account_set_audio_codecs(acc: String, codecs: String): Int
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
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.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.LinearLayout.LayoutParams
|
||||||
|
import android.widget.*
|
||||||
|
|
||||||
|
class AccountActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
internal lateinit var acc: Account
|
||||||
|
internal lateinit var displayName: EditText
|
||||||
|
internal lateinit var aor: String
|
||||||
|
internal lateinit var authUser: EditText
|
||||||
|
internal lateinit var authPass: EditText
|
||||||
|
internal lateinit var outbound1: EditText
|
||||||
|
internal lateinit var outbound2: EditText
|
||||||
|
internal lateinit var regint: EditText
|
||||||
|
internal lateinit var mediaEnc: String
|
||||||
|
|
||||||
|
private var newCodecs = ArrayList<String>()
|
||||||
|
private var save = false
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_account)
|
||||||
|
|
||||||
|
val b = intent.extras
|
||||||
|
acc = Account.find(MainActivity.uas, b.getString("accp"))!!
|
||||||
|
aor = acc.aor
|
||||||
|
setTitle(aor.replace("sip:", ""))
|
||||||
|
|
||||||
|
displayName = findViewById(R.id.DisplayName) as EditText
|
||||||
|
displayName.setText(acc.displayName)
|
||||||
|
|
||||||
|
authUser = findViewById(R.id.AuthUser) as EditText
|
||||||
|
authUser.setText(acc.authUser)
|
||||||
|
|
||||||
|
authPass = findViewById(R.id.AuthPass) as EditText
|
||||||
|
authPass.setText(acc.authPass)
|
||||||
|
|
||||||
|
outbound1 = findViewById(R.id.Outbound1) as EditText
|
||||||
|
outbound2 = findViewById(R.id.Outbound2) as EditText
|
||||||
|
if (acc.outbound.size > 0) {
|
||||||
|
outbound1.setText(acc.outbound[0])
|
||||||
|
if (acc.outbound.size > 1)
|
||||||
|
outbound2.setText(acc.outbound[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
regint = findViewById(R.id.RegInt) as EditText
|
||||||
|
regint.setText(acc.regint.toString())
|
||||||
|
|
||||||
|
val audioCodecs = ArrayList(Utils.audio_codecs().split(","))
|
||||||
|
newCodecs.addAll(audioCodecs)
|
||||||
|
while (newCodecs.size < audioCodecs.size) newCodecs.add("")
|
||||||
|
|
||||||
|
val layout = findViewById(R.id.CodecSpinners) as LinearLayout
|
||||||
|
for (i in audioCodecs.indices) {
|
||||||
|
val spinner = Spinner(applicationContext)
|
||||||
|
spinner.id = i + 100
|
||||||
|
spinner.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
||||||
|
spinner.setPopupBackgroundResource(R.drawable.spinner_background)
|
||||||
|
layout.addView(spinner)
|
||||||
|
|
||||||
|
var spinnerList = ArrayList<String>()
|
||||||
|
if (acc.audioCodec.size > i) {
|
||||||
|
val codec = acc.audioCodec[i]
|
||||||
|
spinnerList.add(codec)
|
||||||
|
for (c in audioCodecs) if (c != codec) spinnerList.add(c)
|
||||||
|
spinnerList.add("")
|
||||||
|
} else {
|
||||||
|
spinnerList = audioCodecs
|
||||||
|
spinnerList.add(0, "")
|
||||||
|
}
|
||||||
|
val codecSpinner = findViewById(spinner.id) as Spinner
|
||||||
|
val adapter = ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,
|
||||||
|
spinnerList)
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
|
codecSpinner.adapter = adapter
|
||||||
|
codecSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||||
|
newCodecs.set(parent.id - 100, parent.selectedItem.toString())
|
||||||
|
}
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaEnc = acc.mediaenc
|
||||||
|
val mediaEncSpinner = findViewById(R.id.mediaEncSpinner) as Spinner
|
||||||
|
val mediaEncKeys = arrayListOf("zrtp", "dtls_srtp", "srtp", "srtp-mand", "")
|
||||||
|
val mediaEncVals = arrayListOf("ZRTP", "DTLS SRTP", "SRTP", "Madatory SRTP", "")
|
||||||
|
val keyIx = mediaEncKeys.indexOf(acc.mediaenc)
|
||||||
|
val keyVal = mediaEncVals.elementAt(keyIx)
|
||||||
|
mediaEncKeys.removeAt(keyIx)
|
||||||
|
mediaEncVals.removeAt(keyIx)
|
||||||
|
mediaEncKeys.add(0, acc.mediaenc)
|
||||||
|
mediaEncVals.add(0, keyVal)
|
||||||
|
val mediaEncAdapter = ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,
|
||||||
|
mediaEncVals)
|
||||||
|
mediaEncAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
|
mediaEncSpinner.adapter = mediaEncAdapter
|
||||||
|
mediaEncSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||||
|
mediaEnc = mediaEncKeys[mediaEncVals.indexOf(parent.selectedItem.toString())]
|
||||||
|
}
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 intent = Intent(this, MainActivity::class.java)
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.save -> {
|
||||||
|
val dn = displayName.text.toString().trim()
|
||||||
|
if (dn != acc.displayName) {
|
||||||
|
if (checkDisplayName(dn)) {
|
||||||
|
if (account_set_display_name(acc.accp, dn) == 0) {
|
||||||
|
acc.displayName = account_display_name(acc.accp);
|
||||||
|
Log.d("Baresip", "New display name is ${acc.displayName}")
|
||||||
|
save = true
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Setting of display name failed")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Utils.alertView(this, "Notice", "Invalid Display Name: $dn")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val au = authUser.text.toString().trim()
|
||||||
|
if (au != acc.authUser) {
|
||||||
|
if (checkAuthUser(au)) {
|
||||||
|
if (account_set_auth_user(acc.accp, au) == 0) {
|
||||||
|
acc.authUser = account_auth_user(acc.accp);
|
||||||
|
Log.d("Baresip", "New auth user is ${acc.authUser}")
|
||||||
|
save = true
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Setting of auth user failed")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Utils.alertView(this, "Notice",
|
||||||
|
"Invalid Authentication UserName: $au")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ap = authPass.text.toString().trim()
|
||||||
|
if (ap != acc.authPass) {
|
||||||
|
if (Utils.checkPrintASCII(ap)) {
|
||||||
|
if (account_set_auth_pass(acc.accp, ap) == 0) {
|
||||||
|
acc.authPass = account_auth_pass(acc.accp)
|
||||||
|
Log.d("Baresip", "New auth password is ${acc.authPass}")
|
||||||
|
save = true
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Setting of auth pass failed")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Utils.alertView(this, "Notice",
|
||||||
|
"Invalid Authentication Password: $ap")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ob = ArrayList<String>()
|
||||||
|
if (outbound1.text.toString().trim() != "")
|
||||||
|
ob.add(outbound1.text.toString().trim().replace(" ", ""))
|
||||||
|
if (outbound2.text.toString().trim() != "")
|
||||||
|
ob.add(outbound2.text.toString().trim().replace(" ", ""))
|
||||||
|
if (ob != acc.outbound) {
|
||||||
|
val outbound = ArrayList<String>()
|
||||||
|
for (i in ob.indices) {
|
||||||
|
if ((ob[i] == "") || Utils.uri_decode(ob[i])) {
|
||||||
|
if (account_set_outbound(acc.accp, ob[i], i) == 0) {
|
||||||
|
if (ob[i] != "")
|
||||||
|
outbound.add(account_outbound(acc.accp, i))
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Setting of outbound proxy ${ob[i]} failed")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Utils.alertView(this, "Notice",
|
||||||
|
"Invalid Outbound Proxy: ${ob[i]}")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d("Baresip", "New outbound proxies are ${outbound}")
|
||||||
|
acc.outbound = outbound
|
||||||
|
save = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val ri = regint.text.toString().trim()
|
||||||
|
if (Utils.checkUint(ri)) {
|
||||||
|
if (ri.toInt() != acc.regint) {
|
||||||
|
if (account_set_regint(acc.accp, ri.toInt()) == 0) {
|
||||||
|
acc.regint = account_regint(acc.accp)
|
||||||
|
Log.d("Baresip", "New regint is ${acc.regint}")
|
||||||
|
save = true
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Setting of regint $ri failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Utils.alertView(this, "Notice",
|
||||||
|
"Invalid Registration Interval: $ri")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val ac = ArrayList(LinkedHashSet<String>(newCodecs.filter{it != ""} as ArrayList<String>))
|
||||||
|
if (ac != acc.audioCodec) {
|
||||||
|
Log.d("Baresip", "New codecs ${newCodecs.filter { it != "" }}")
|
||||||
|
val acParam = ";audio_codecs=" + Utils.implode(ac, ",")
|
||||||
|
if (account_set_audio_codecs(acc.accp, acParam) == 0) {
|
||||||
|
var i = 0
|
||||||
|
while (true) {
|
||||||
|
val codec = account_audio_codec(acc.accp, i)
|
||||||
|
if (codec != "") {
|
||||||
|
Log.d("Baresip", "Found audio codec $codec")
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc.audioCodec = ac
|
||||||
|
save = true
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Setting of audio codecs $acParam failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaEnc != acc.mediaenc) {
|
||||||
|
if (account_set_mediaenc(acc.accp, mediaEnc) == 0) {
|
||||||
|
acc.mediaenc = account_mediaenc(acc.accp)
|
||||||
|
Log.d("Baresip", "New mediaenc is ${acc.mediaenc}")
|
||||||
|
save = true
|
||||||
|
} else {
|
||||||
|
Log.e("Baresip", "Setting of mediaenc $mediaEnc failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save) {
|
||||||
|
AccountsActivity.saveAccounts()
|
||||||
|
if (acc.regint > 0) {
|
||||||
|
Log.d("Baresip", "Registering ${acc.aor}")
|
||||||
|
UserAgent.ua_register(Account.findUA(acc.aor)!!.uap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setResult(RESULT_OK, intent)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.cancel, android.R.id.home -> {
|
||||||
|
intent.putExtra("action", "cancel")
|
||||||
|
if (acc.regint > 0) {
|
||||||
|
Log.d("Baresip", "Registering ${acc.aor}")
|
||||||
|
UserAgent.ua_register(Account.findUA(acc.aor)!!.uap)
|
||||||
|
}
|
||||||
|
setResult(RESULT_OK, intent)
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkDisplayName(dn: String): Boolean {
|
||||||
|
if (dn == "") return true
|
||||||
|
val dnRegex = Regex("^[a-zA-Z]([ ._-]|[a-zA-Z0-9]){1,63}\$")
|
||||||
|
return dnRegex.matches(dn)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkAuthUser(au: String): Boolean {
|
||||||
|
if (au == "") return true
|
||||||
|
val ud = au.split("@")
|
||||||
|
val userIDRegex = Regex("^[a-zA-Z]([._-]|[a-zA-Z0-9]){1,63}\$")
|
||||||
|
val telnoRegex = Regex("^[+]?[0-9]{1,16}\$")
|
||||||
|
if (ud.size == 1) {
|
||||||
|
return userIDRegex.matches(ud[0]) || telnoRegex.matches(ud[0])
|
||||||
|
} else {
|
||||||
|
return (userIDRegex.matches(ud[0]) || telnoRegex.matches(ud[0])) &&
|
||||||
|
Utils.checkDomain(ud[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AlertDialog
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.ImageButton
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class AccountListAdapter(private val cxt: Context, private val rows: ArrayList<AccountRow>) :
|
||||||
|
ArrayAdapter<AccountRow>(cxt, R.layout.account_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.account_row, parent, false)
|
||||||
|
val aorView = rowView.findViewById(R.id.aor) as TextView
|
||||||
|
aorView.text = row.aor
|
||||||
|
aorView.textSize = 20f
|
||||||
|
aorView.setPadding(6, 6, 0, 6)
|
||||||
|
aorView.setOnClickListener { _ ->
|
||||||
|
val i = Intent(cxt, AccountActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("accp", MainActivity.uas[position].account.accp)
|
||||||
|
i.putExtras(b)
|
||||||
|
cxt.startActivity(i)
|
||||||
|
}
|
||||||
|
val actionView = rowView.findViewById(R.id.action) as ImageButton
|
||||||
|
actionView.setImageResource(row.action)
|
||||||
|
actionView.setOnClickListener { _ ->
|
||||||
|
Log.d("Baresip", "Delete button clicked")
|
||||||
|
val deleteDialog = AlertDialog.Builder(cxt)
|
||||||
|
deleteDialog.setMessage("Do you want to delete account ${MainActivity.uas[position].aor}?")
|
||||||
|
deleteDialog.setPositiveButton("Delete") { dialog, _ ->
|
||||||
|
if (UserAgent.ua_isregistered(MainActivity.uas[position].uap)) {
|
||||||
|
UserAgent.ua_unregister(MainActivity.uas[position].uap)
|
||||||
|
}
|
||||||
|
UserAgent.ua_destroy(MainActivity.uas[position].uap)
|
||||||
|
MainActivity.uas.remove(MainActivity.uas[position])
|
||||||
|
MainActivity.images.removeAt(position)
|
||||||
|
AccountsActivity.saveAccounts()
|
||||||
|
AccountsActivity.generateAccounts()
|
||||||
|
this.notifyDataSetChanged()
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
deleteDialog.setNegativeButton("No") { dialog, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
deleteDialog.create().show()
|
||||||
|
}
|
||||||
|
return rowView
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
class AccountRow(val aor: String, val action: Int)
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.SystemClock
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.widget.*
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
class AccountsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
internal var aor: String = ""
|
||||||
|
|
||||||
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_accounts)
|
||||||
|
|
||||||
|
val listview = findViewById(R.id.accounts) as ListView
|
||||||
|
generateAccounts()
|
||||||
|
val alAdapter = AccountListAdapter(this, accounts)
|
||||||
|
listview.adapter = alAdapter
|
||||||
|
|
||||||
|
val addAccountButton = findViewById(R.id.addAccount) as ImageButton
|
||||||
|
val newAorView = findViewById(R.id.newAor) as EditText
|
||||||
|
addAccountButton.setOnClickListener{
|
||||||
|
var aor = newAorView.text.toString()
|
||||||
|
if (!aor.startsWith("sip:")) aor = "sip:$aor"
|
||||||
|
if (!checkSipUri(aor)) {
|
||||||
|
Log.e("Baresip", "Invalid SIP URI $aor")
|
||||||
|
Utils.alertView(this, "Notice",
|
||||||
|
"Invalid SIP URI: $aor")
|
||||||
|
} else if (Account.exists(MainActivity.uas, aor)) {
|
||||||
|
Log.e("Baresip", "Account $aor already exists")
|
||||||
|
} else {
|
||||||
|
if (UserAgent.ua_alloc("<$aor>;regq=0.5;pubint=0;regint=600") != 0)
|
||||||
|
Log.e("Baresip", "Failed to allocate UA $aor")
|
||||||
|
else {
|
||||||
|
SystemClock.sleep(200);
|
||||||
|
newAorView.setText("")
|
||||||
|
newAorView.setHint("SIP URI user@domain")
|
||||||
|
newAorView.clearFocus()
|
||||||
|
saveAccounts()
|
||||||
|
recreate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
android.R.id.home -> {
|
||||||
|
Log.d("Baresip", "Back array was pressed at Accounts")
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkSipUri(uri: String): Boolean {
|
||||||
|
if (!uri.startsWith("sip:")) return false
|
||||||
|
val userDomain = uri.replace("sip:", "").split("@")
|
||||||
|
if (userDomain.size != 2) return false
|
||||||
|
if (!Utils.checkUserID(userDomain[0]) && !Utils.checkTelNo(userDomain[0]))
|
||||||
|
return false
|
||||||
|
return Utils.checkDomain(userDomain[1]) || Utils.checkIP(userDomain[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
var accounts = ArrayList<AccountRow>()
|
||||||
|
var posAtAccounts = ArrayList<Int>()
|
||||||
|
|
||||||
|
fun generateAccounts() {
|
||||||
|
accounts.clear()
|
||||||
|
posAtAccounts.clear()
|
||||||
|
var i = 0;
|
||||||
|
for (ua in MainActivity.uas) {
|
||||||
|
accounts.add(AccountRow(ua.aor.replace("sip:", ""), R.drawable.action_remove))
|
||||||
|
posAtAccounts.add(i)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveAccounts() {
|
||||||
|
var accounts = ""
|
||||||
|
for (a in Account.accounts()) accounts = accounts + a.print() + "\n"
|
||||||
|
val path = MainActivity.filesPath + "/accounts"
|
||||||
|
Utils.putFileContents(File(path), accounts)
|
||||||
|
Log.d("Baresip", "Saved accounts '${accounts}' to '$path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,31 +3,47 @@ package com.tutpro.baresip
|
|||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
class Call(val ua: String, val call: String, val peerURI: String, var status: String,
|
class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: String,
|
||||||
val dtmfWatcher: TextWatcher?) {
|
var status: String, val dtmfWatcher: TextWatcher?) {
|
||||||
|
|
||||||
var hold: Boolean = false
|
var hold = false
|
||||||
var security: Int = 0
|
var security = 0
|
||||||
var zid: String = ""
|
var zid = ""
|
||||||
|
var hasHistory = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun uaCalls(calls: ArrayList<Call>, ua: String): ArrayList<Call> {
|
fun calls(calls: ArrayList<Call>, dir: String): ArrayList<Call> {
|
||||||
val result = ArrayList<Call>()
|
val result = ArrayList<Call>()
|
||||||
for (i in calls.indices) {
|
for (i in calls.indices) {
|
||||||
if (calls[i].ua == ua) result.add(calls[i])
|
if (calls[i].dir == dir) result.add(calls[i])
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun callIndex(calls: ArrayList<Call>, ua: String, call: String): Int {
|
fun uaCalls(calls: ArrayList<Call>, ua: UserAgent, dir: String): ArrayList<Call> {
|
||||||
|
val result = ArrayList<Call>()
|
||||||
for (i in calls.indices) {
|
for (i in calls.indices) {
|
||||||
if (calls[i].ua.equals(ua) && calls[i].call == call)
|
if ((calls[i].ua == ua) && (calls[i].dir == dir)) result.add(calls[i])
|
||||||
return i
|
|
||||||
}
|
}
|
||||||
return -1
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun find(calls: ArrayList<Call>, callp: String): Call? {
|
||||||
|
for (c in calls) {
|
||||||
|
if (c.callp == callp) return c
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun index(calls: ArrayList<Call>, call: Call, dir: String): Int {
|
||||||
|
var res = 0
|
||||||
|
for (c in calls) {
|
||||||
|
if (c == call) return res
|
||||||
|
if ((dir == "") || (call.dir == dir)) res++
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
class Codec(val name: String, val rate: Int, val channels: Int) {}
|
||||||
@@ -1,103 +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
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -3,8 +3,8 @@ package com.tutpro.baresip
|
|||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.util.GregorianCalendar
|
import java.util.GregorianCalendar
|
||||||
|
|
||||||
class History(val ua: String, val call: String, val aor: String, val peerURI: String,
|
class History(val aor: String, val peerURI: String, val direction: String,
|
||||||
val direction: String, val connected: Boolean) : Serializable {
|
val connected: Boolean) : Serializable {
|
||||||
|
|
||||||
val time: GregorianCalendar = GregorianCalendar()
|
val time: GregorianCalendar = GregorianCalendar()
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class HistoryActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val b = intent.extras
|
val b = intent.extras
|
||||||
aor = b.getString("aor")
|
aor = b.getString("aor")
|
||||||
generate_ua_history(aor)
|
aorGenerateHistory(aor)
|
||||||
|
|
||||||
val adapter = HistoryListAdapter(this, uaHistory)
|
val adapter = HistoryListAdapter(this, uaHistory)
|
||||||
listview.adapter = adapter
|
listview.adapter = adapter
|
||||||
@@ -46,7 +46,7 @@ class HistoryActivity : AppCompatActivity() {
|
|||||||
when (which) {
|
when (which) {
|
||||||
DialogInterface.BUTTON_POSITIVE -> {
|
DialogInterface.BUTTON_POSITIVE -> {
|
||||||
History.removeAt(posAtHistory[pos])
|
History.removeAt(posAtHistory[pos])
|
||||||
generate_ua_history(aor)
|
aorGenerateHistory(aor)
|
||||||
if (uaHistory.size == 0) {
|
if (uaHistory.size == 0) {
|
||||||
val i = Intent()
|
val i = Intent()
|
||||||
setResult(Activity.RESULT_CANCELED, i)
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
@@ -82,7 +82,7 @@ class HistoryActivity : AppCompatActivity() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generate_ua_history(aor: String) {
|
private fun aorGenerateHistory(aor: String) {
|
||||||
uaHistory.clear()
|
uaHistory.clear()
|
||||||
posAtHistory.clear()
|
posAtHistory.clear()
|
||||||
for (i in History.indices.reversed()) {
|
for (i in History.indices.reversed()) {
|
||||||
@@ -137,13 +137,6 @@ class HistoryActivity : AppCompatActivity() {
|
|||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun callHasHistory(ua: String, call: String): Boolean {
|
|
||||||
for (h in History) {
|
|
||||||
if (h.ua == ua && h.call == call) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun aorRemoveHistory(aor: String) {
|
fun aorRemoveHistory(aor: String) {
|
||||||
for (h in History) {
|
for (h in History) {
|
||||||
if (h.aor == aor) {
|
if (h.aor == aor) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Notification
|
|
||||||
import android.app.Notification.VISIBILITY_PUBLIC
|
import android.app.Notification.VISIBILITY_PUBLIC
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
@@ -35,14 +34,14 @@ import java.io.*
|
|||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
internal lateinit var appContext: Context
|
lateinit var appContext: Context
|
||||||
internal lateinit var layout: RelativeLayout
|
internal lateinit var layout: RelativeLayout
|
||||||
internal lateinit var callee: AutoCompleteTextView
|
internal lateinit var callee: AutoCompleteTextView
|
||||||
internal lateinit var securityButton: ImageButton
|
internal lateinit var securityButton: ImageButton
|
||||||
internal lateinit var callButton: Button
|
internal lateinit var callButton: Button
|
||||||
internal lateinit var holdButton: Button
|
internal lateinit var holdButton: Button
|
||||||
internal lateinit var dtmf: EditText
|
internal lateinit var dtmf: EditText
|
||||||
internal lateinit var accountAdapter: AccountSpinnerAdapter
|
internal lateinit var uaAdapter: UaSpinnerAdapter
|
||||||
internal lateinit var aorSpinner: Spinner
|
internal lateinit var aorSpinner: Spinner
|
||||||
internal lateinit var am: AudioManager
|
internal lateinit var am: AudioManager
|
||||||
internal lateinit var imm: InputMethodManager
|
internal lateinit var imm: InputMethodManager
|
||||||
@@ -61,6 +60,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
callButton = findViewById(R.id.callButton) as Button
|
callButton = findViewById(R.id.callButton) as Button
|
||||||
holdButton = findViewById(R.id.holdButton) as Button
|
holdButton = findViewById(R.id.holdButton) as Button
|
||||||
dtmf = findViewById(R.id.dtmf) as EditText
|
dtmf = findViewById(R.id.dtmf) as EditText
|
||||||
|
filesPath = applicationContext.filesDir.absolutePath
|
||||||
|
|
||||||
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
@@ -78,15 +78,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.setContent(RemoteViews(getPackageName(), R.layout.notification))
|
.setContent(RemoteViews(getPackageName(), R.layout.notification))
|
||||||
|
|
||||||
aorSpinner = findViewById(R.id.AoRList) as Spinner
|
aorSpinner = findViewById(R.id.AoRList) as Spinner
|
||||||
accountAdapter = AccountSpinnerAdapter(applicationContext, accounts, images)
|
uaAdapter = UaSpinnerAdapter(applicationContext, uas, images)
|
||||||
aorSpinner.adapter = accountAdapter
|
aorSpinner.adapter = uaAdapter
|
||||||
aorSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
aorSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||||
val aor = accounts[position].aoR
|
val acc = uas[position].account
|
||||||
val ua = accounts[position].ua
|
val aor = acc.aor
|
||||||
|
val ua = uas[position]
|
||||||
Log.i("Baresip", "Setting $aor current")
|
Log.i("Baresip", "Setting $aor current")
|
||||||
val out = Call.uaCalls(callsOut, ua)
|
val callsOut = Call.uaCalls(calls, ua, "out")
|
||||||
if (out.size == 0) {
|
if (callsOut.size == 0) {
|
||||||
callee.text.clear()
|
callee.text.clear()
|
||||||
callee.hint = "Callee"
|
callee.hint = "Callee"
|
||||||
callButton.text = "Call"
|
callButton.text = "Call"
|
||||||
@@ -99,18 +100,18 @@ class MainActivity : AppCompatActivity() {
|
|||||||
securityButton.visibility = View.INVISIBLE
|
securityButton.visibility = View.INVISIBLE
|
||||||
dtmf.visibility = View.INVISIBLE
|
dtmf.visibility = View.INVISIBLE
|
||||||
} else {
|
} else {
|
||||||
callee.setText(out[0].peerURI)
|
callee.setText(callsOut[0].peerURI)
|
||||||
callButton.text = out[0].status
|
callButton.text = callsOut[0].status
|
||||||
if (out[0].status == "Hangup") {
|
if (callsOut[0].status == "Hangup") {
|
||||||
if (out[0].hold) {
|
if (callsOut[0].hold) {
|
||||||
holdButton.text = "Unhold"
|
holdButton.text = "Unhold"
|
||||||
} else {
|
} else {
|
||||||
holdButton.text = "Hold"
|
holdButton.text = "Hold"
|
||||||
}
|
}
|
||||||
holdButton.visibility = View.VISIBLE
|
holdButton.visibility = View.VISIBLE
|
||||||
securityButton.setImageResource(out[0].security)
|
securityButton.setImageResource(callsOut[0].security)
|
||||||
Utils.setSecurityButtonTag(securityButton, out[0].security)
|
setSecurityButtonTag(securityButton, callsOut[0].security)
|
||||||
if (ua_mediaenc(ua) == "")
|
if (acc.mediaenc == "")
|
||||||
securityButton.visibility = View.INVISIBLE
|
securityButton.visibility = View.INVISIBLE
|
||||||
else
|
else
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
@@ -122,7 +123,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
dtmf.visibility = View.INVISIBLE
|
dtmf.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val `in` = Call.uaCalls(callsIn, ua)
|
val `in` = Call.uaCalls(calls, ua, "in")
|
||||||
val view_count = layout.childCount
|
val view_count = layout.childCount
|
||||||
Log.d("Baresip", "View count is $view_count")
|
Log.d("Baresip", "View count is $view_count")
|
||||||
if (view_count > 7) {
|
if (view_count > 7) {
|
||||||
@@ -130,7 +131,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
layout.removeViews(7, view_count - 7)
|
layout.removeViews(7, view_count - 7)
|
||||||
}
|
}
|
||||||
for (c in `in`) {
|
for (c in `in`) {
|
||||||
for (call_index in callsIn.indices) {
|
for (call_index in Call.calls(calls, "in").indices) {
|
||||||
addCallViews(ua, c, (call_index + 1) * 10)
|
addCallViews(ua, c, (call_index + 1) * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,6 +142,23 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aorSpinner.setOnTouchListener { view, event ->
|
||||||
|
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||||
|
if ((event.x - view.left) < 100) {
|
||||||
|
val i = Intent(this, AccountActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("accp", uas[aorSpinner.selectedItemPosition].account.accp)
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivityForResult(i, ACCOUNT_CODE)
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val assets = arrayOf("accounts", "contacts", "config", "busy.wav", "callwaiting.wav",
|
val assets = arrayOf("accounts", "contacts", "config", "busy.wav", "callwaiting.wav",
|
||||||
"error.wav", "message.wav", "notfound.wav", "ring.wav", "ringback.wav")
|
"error.wav", "message.wav", "notfound.wav", "ring.wav", "ringback.wav")
|
||||||
val path = applicationContext.filesDir.path
|
val path = applicationContext.filesDir.path
|
||||||
@@ -159,7 +177,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
file = File("$path/$a")
|
file = File("$path/$a")
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
Log.d("Baresip", "Copying asset $a")
|
Log.d("Baresip", "Copying asset $a")
|
||||||
Utils.copyAssetToFile(applicationContext, a, "$path/$a")
|
copyAssetToFile(applicationContext, a, "$path/$a")
|
||||||
} else {
|
} else {
|
||||||
Log.d("Baresip", "Asset $a already copied")
|
Log.d("Baresip", "Asset $a already copied")
|
||||||
}
|
}
|
||||||
@@ -207,11 +225,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " +
|
unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " +
|
||||||
"Do you want to unverify the peer?")
|
"Do you want to unverify the peer?")
|
||||||
unverifyDialog.setPositiveButton("Unverify") { dialog, _ ->
|
unverifyDialog.setPositiveButton("Unverify") { dialog, _ ->
|
||||||
val out = Call.uaCalls(callsOut, accounts[aorSpinner.selectedItemPosition].ua)
|
val outCalls = Call.uaCalls(calls, uas[aorSpinner.selectedItemPosition], "out")
|
||||||
if (out.size > 0) {
|
if (outCalls.size > 0) {
|
||||||
if (cmd_exec("zrtp_unverify " + out[0].zid) != 0) {
|
if (Utils.cmd_exec("zrtp_unverify " + outCalls[0].zid) != 0) {
|
||||||
Log.w("Baresip",
|
Log.w("Baresip",
|
||||||
"Command 'zrtp_unverify ${out[0].zid}' failed")
|
"Command 'zrtp_unverify ${outCalls[0].zid}' failed")
|
||||||
} else {
|
} else {
|
||||||
securityButton.setImageResource(R.drawable.box_yellow)
|
securityButton.setImageResource(R.drawable.box_yellow)
|
||||||
securityButton.tag = "yellow"
|
securityButton.tag = "yellow"
|
||||||
@@ -229,8 +247,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
callButton.text = "Call"
|
callButton.text = "Call"
|
||||||
callButton.setOnClickListener {
|
callButton.setOnClickListener {
|
||||||
val aor = accounts[aorSpinner.selectedItemPosition].aoR
|
val ua = uas[aorSpinner.selectedItemPosition]
|
||||||
val ua = accounts[aorSpinner.selectedItemPosition].ua
|
val aor = ua.aor
|
||||||
when (callButton.text.toString()) {
|
when (callButton.text.toString()) {
|
||||||
"Call" -> {
|
"Call" -> {
|
||||||
val callee = (findViewById(R.id.callee) as EditText).text.toString()
|
val callee = (findViewById(R.id.callee) as EditText).text.toString()
|
||||||
@@ -245,14 +263,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"Cancel" -> {
|
"Cancel" -> {
|
||||||
Log.i("Baresip", "Canceling AoR $aor call " +
|
val callp = Call.calls(calls, "out")[0].callp
|
||||||
callsOut[0].call + " to " + (findViewById(R.id.callee) as EditText).text)
|
Log.i("Baresip", "Canceling AoR $aor call $callp to " +
|
||||||
ua_hangup(ua, callsOut[0].call, 486, "Rejected")
|
(findViewById(R.id.callee) as EditText).text)
|
||||||
|
ua_hangup(ua.uap, callp, 486, "Rejected")
|
||||||
}
|
}
|
||||||
"Hangup" -> {
|
"Hangup" -> {
|
||||||
Log.i("Baresip", "Hanging up AoR $aor call " +
|
val callp = Call.calls(calls, "out")[0].callp
|
||||||
callsOut[0].call + " to " + (findViewById(R.id.callee) as EditText).text)
|
Log.i("Baresip", "Hanging up AoR $aor call $callp to " +
|
||||||
ua_hangup(ua, callsOut[0].call,0, "")
|
(findViewById(R.id.callee) as EditText).text)
|
||||||
|
ua_hangup(ua.uap, callp,0, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,20 +282,22 @@ class MainActivity : AppCompatActivity() {
|
|||||||
when (holdButton.text.toString()) {
|
when (holdButton.text.toString()) {
|
||||||
"Hold" -> {
|
"Hold" -> {
|
||||||
Log.i("Baresip", "Holding up " + (findViewById(R.id.callee) as EditText).text)
|
Log.i("Baresip", "Holding up " + (findViewById(R.id.callee) as EditText).text)
|
||||||
call_hold(callsOut[0].call)
|
val call = Call.calls(calls, "out")[0]
|
||||||
callsOut[0].hold = true
|
call_hold(call.callp)
|
||||||
|
call.hold = true
|
||||||
holdButton.text = "Unhold"
|
holdButton.text = "Unhold"
|
||||||
}
|
}
|
||||||
"Unhold" -> {
|
"Unhold" -> {
|
||||||
Log.i("Baresip", "Unholding " + (findViewById(R.id.callee) as EditText).text)
|
Log.i("Baresip", "Unholding " + (findViewById(R.id.callee) as EditText).text)
|
||||||
call_unhold(callsOut[0].call)
|
val call = Call.calls(calls, "out")[0]
|
||||||
callsOut[0].hold = false
|
call_unhold(call.callp)
|
||||||
|
call.hold = false
|
||||||
holdButton.text = "Hold"
|
holdButton.text = "Hold"
|
||||||
}
|
}
|
||||||
"History" -> {
|
"History" -> {
|
||||||
val i = Intent(this@MainActivity, HistoryActivity::class.java)
|
val i = Intent(this@MainActivity, HistoryActivity::class.java)
|
||||||
val b = Bundle()
|
val b = Bundle()
|
||||||
b.putString("aor", accounts[aorSpinner.selectedItemPosition].aoR)
|
b.putString("aor", uas[aorSpinner.selectedItemPosition].aor)
|
||||||
i.putExtras(b)
|
i.putExtras(b)
|
||||||
startActivityForResult(i, HISTORY_CODE)
|
startActivityForResult(i, HISTORY_CODE)
|
||||||
}
|
}
|
||||||
@@ -337,8 +359,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.accounts -> {
|
R.id.accounts -> {
|
||||||
i = Intent(this, EditAccountsActivity::class.java)
|
i = Intent(this, AccountsActivity::class.java)
|
||||||
startActivityForResult(i, EDIT_ACCOUNTS_CODE)
|
startActivityForResult(i, ACCOUNTS_CODE)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.contacts -> {
|
R.id.contacts -> {
|
||||||
@@ -372,7 +394,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
Log.w("Baresip", "OutputStream exception: " + e.toString())
|
Log.w("Baresip", "OutputStream exception: " + e.toString())
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
baresipStop()
|
baresipStop()
|
||||||
nm.cancel(10)
|
nm.cancel(10)
|
||||||
running = false
|
running = false
|
||||||
@@ -389,15 +410,12 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
|
|
||||||
EDIT_ACCOUNTS_CODE -> {
|
ACCOUNTS_CODE -> {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK)
|
||||||
Utils.alertView(this, "Notice",
|
Log.d("Baresip", "Edit accounts OK")
|
||||||
"You need to restart baresip in order to activate saved accounts!")
|
if (resultCode == RESULT_CANCELED)
|
||||||
}
|
|
||||||
if (resultCode == RESULT_CANCELED) {
|
|
||||||
Log.d("Baresip", "Edit accounts canceled")
|
Log.d("Baresip", "Edit accounts canceled")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
EDIT_CONFIG_CODE -> {
|
EDIT_CONFIG_CODE -> {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
@@ -418,7 +436,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
if (resultCode == RESULT_CANCELED) {
|
if (resultCode == RESULT_CANCELED) {
|
||||||
Log.d("Baresip", "History canceled")
|
Log.d("Baresip", "History canceled")
|
||||||
if (HistoryActivity.aorHistory(accounts[aorSpinner.selectedItemPosition].aoR) == 0) {
|
if (HistoryActivity.aorHistory(uas[aorSpinner.selectedItemPosition].aor) == 0) {
|
||||||
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -430,12 +448,12 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun call(ua: String, uri: String) {
|
private fun call(ua: UserAgent, uri: String) {
|
||||||
(findViewById(R.id.callee) as EditText).setText(uri)
|
(findViewById(R.id.callee) as EditText).setText(uri)
|
||||||
Log.i("Baresip", "Calling $ua / $uri")
|
Log.i("Baresip", "Calling $ua.uap / $uri")
|
||||||
val call = ua_connect(ua, uri)
|
val call = ua_connect(ua.uap, uri)
|
||||||
if (call != "") {
|
if (call != "") {
|
||||||
Log.i("Baresip", "Adding outgoing call $ua / $call / $uri")
|
Log.i("Baresip", "Adding outgoing call $ua.uap / $call / $uri")
|
||||||
val dtmfWatcher = object: TextWatcher {
|
val dtmfWatcher = object: TextWatcher {
|
||||||
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
|
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
@@ -447,15 +465,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
call_send_digit(call, 4.toChar())
|
call_send_digit(call, 4.toChar())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callsOut.add(Call(ua, call, uri, "Cancel", dtmfWatcher))
|
calls.add(Call(call, ua, uri, "out","Cancel", dtmfWatcher))
|
||||||
(findViewById(R.id.callButton) as Button).text = "Cancel"
|
(findViewById(R.id.callButton) as Button).text = "Cancel"
|
||||||
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addCallViews(ua: String, call: Call, id: Int) {
|
private fun addCallViews(ua: UserAgent, call: Call, id: Int) {
|
||||||
Log.d("Baresip", "Creating new Incoming textview at $id")
|
Log.d("Baresip", "Creating new Incoming textview at $id")
|
||||||
|
|
||||||
|
val acc = ua.account
|
||||||
val caller_heading = TextView(appContext)
|
val caller_heading = TextView(appContext)
|
||||||
caller_heading.text = "Incoming call from ..."
|
caller_heading.text = "Incoming call from ..."
|
||||||
caller_heading.setTextColor(Color.BLACK)
|
caller_heading.setTextColor(Color.BLACK)
|
||||||
@@ -480,7 +499,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
caller_row.layoutParams = caller_row_params
|
caller_row.layoutParams = caller_row_params
|
||||||
|
|
||||||
val caller_uri = TextView(appContext)
|
val caller_uri = TextView(appContext)
|
||||||
caller_uri.text = callsIn[callsIn.size - 1].peerURI
|
caller_uri.text = call.peerURI
|
||||||
caller_uri.setTextColor(Color.BLUE)
|
caller_uri.setTextColor(Color.BLUE)
|
||||||
caller_uri.textSize = 20f
|
caller_uri.textSize = 20f
|
||||||
caller_uri.setPadding(10, 10, 0, 10)
|
caller_uri.setPadding(10, 10, 0, 10)
|
||||||
@@ -497,14 +516,42 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val security_button_params = LinearLayout.LayoutParams(dp24px, dp24px, 0.0f)
|
val security_button_params = LinearLayout.LayoutParams(dp24px, dp24px, 0.0f)
|
||||||
security_button_params.gravity = Gravity.CENTER_VERTICAL
|
security_button_params.gravity = Gravity.CENTER_VERTICAL
|
||||||
security_button.layoutParams = security_button_params
|
security_button.layoutParams = security_button_params
|
||||||
if ((call.security != 0) && (ua_mediaenc(ua) != "")) {
|
if ((call.security != 0) && (acc.mediaenc != "")) {
|
||||||
security_button.setImageResource(call.security)
|
security_button.setImageResource(call.security)
|
||||||
Utils.setSecurityButtonTag(securityButton, call.security)
|
setSecurityButtonTag(securityButton, call.security)
|
||||||
security_button.visibility = View.VISIBLE
|
security_button.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
security_button.visibility = View.INVISIBLE
|
security_button.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
Utils.setSecurityButtonOnClickListener(this, security_button, call)
|
security_button.setOnClickListener {
|
||||||
|
when (security_button.tag) {
|
||||||
|
"red" -> {
|
||||||
|
Utils.alertView(this, "Alert", "This call is NOT secure!")
|
||||||
|
}
|
||||||
|
"yellow" -> {
|
||||||
|
Utils.alertView(this, "Alert",
|
||||||
|
"This call is SECURE, but peer is NOT verified!")
|
||||||
|
}
|
||||||
|
"green" -> {
|
||||||
|
val unverifyDialog = AlertDialog.Builder(this)
|
||||||
|
unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " +
|
||||||
|
"Do you want to unverify the peer?")
|
||||||
|
unverifyDialog.setPositiveButton("Unverify") { dialog, _ ->
|
||||||
|
if (Utils.cmd_exec("zrtp_unverify " + call.zid) != 0) {
|
||||||
|
Log.w("Baresip", "Command 'zrtp_unverify ${call.zid}' failed")
|
||||||
|
} else {
|
||||||
|
security_button.setImageResource(R.drawable.box_yellow)
|
||||||
|
security_button.tag = "yellow"
|
||||||
|
}
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
unverifyDialog.setNegativeButton("No") { dialog, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
unverifyDialog.create().show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
caller_row.addView(security_button)
|
caller_row.addView(security_button)
|
||||||
|
|
||||||
layout.addView(caller_row)
|
layout.addView(caller_row)
|
||||||
@@ -516,20 +563,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
Log.d("Baresip", "Creating new answer button at " + (id + 4))
|
Log.d("Baresip", "Creating new answer button at " + (id + 4))
|
||||||
answer_button.id = id + 4
|
answer_button.id = id + 4
|
||||||
answer_button.setOnClickListener { v ->
|
answer_button.setOnClickListener { v ->
|
||||||
val call_ua = call.ua
|
|
||||||
val call_call = call.call
|
|
||||||
when ((v as Button).text.toString()) {
|
when ((v as Button).text.toString()) {
|
||||||
"Answer" -> {
|
"Answer" -> {
|
||||||
Log.i("Baresip", "UA " + call_ua + " accepting incoming call " +
|
Log.i("Baresip", "UA ${call.ua.uap} accepting incoming call ${call.callp}")
|
||||||
call_call)
|
ua_answer(call.ua.uap, call.callp)
|
||||||
ua_answer(call_ua, call_call)
|
if (call.dir == "in") {
|
||||||
val final_in_index = Call.callIndex(callsIn, call_ua, call_call)
|
|
||||||
if (final_in_index >= 0) {
|
|
||||||
Log.d("Baresip", "Updating Hangup and Hold")
|
Log.d("Baresip", "Updating Hangup and Hold")
|
||||||
callsIn[final_in_index].status = "Hangup"
|
call.status = "Hangup"
|
||||||
callsIn[final_in_index].hold = false
|
call.hold = false
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
val answer_id = (final_in_index + 1) * 10 + 4
|
val answer_id = (Call.index(calls, call,"in") + 1) * 10 + 4
|
||||||
val answer_but = layout.findViewById(answer_id) as Button
|
val answer_but = layout.findViewById(answer_id) as Button
|
||||||
answer_but.text = "Hangup"
|
answer_but.text = "Hangup"
|
||||||
val reject_button = layout.findViewById(answer_id + 1) as Button
|
val reject_button = layout.findViewById(answer_id + 1) as Button
|
||||||
@@ -538,9 +581,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"Hangup" -> {
|
"Hangup" -> {
|
||||||
Log.i("Baresip", "UA " + call_ua + " hanging up call " +
|
Log.i("Baresip", "UA ${call.ua.uap} hanging up call ${call.callp}")
|
||||||
call_call)
|
ua_hangup(call.ua.uap, call.callp, 200, "OK")
|
||||||
ua_hangup(call_ua, call_call, 200, "OK")
|
|
||||||
}
|
}
|
||||||
else -> Log.e("Baresip", "Invalid answer button text: " + v.text.toString())
|
else -> Log.e("Baresip", "Invalid answer button text: " + v.text.toString())
|
||||||
}
|
}
|
||||||
@@ -569,16 +611,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
when ((v as Button).text.toString()) {
|
when ((v as Button).text.toString()) {
|
||||||
"Reject" -> {
|
"Reject" -> {
|
||||||
Log.i("Baresip", "UA " + call.ua +
|
Log.i("Baresip", "UA " + call.ua +
|
||||||
" rejecting incoming call " + call.call)
|
" rejecting incoming call " + call.callp)
|
||||||
ua_hangup(call.ua, call.call, 486, "Rejected")
|
ua_hangup(call.ua.uap, call.callp, 486, "Rejected")
|
||||||
}
|
}
|
||||||
"Hold" -> {
|
"Hold" -> {
|
||||||
call_hold(call.call)
|
call_hold(call.callp)
|
||||||
v.text = "Unhold"
|
v.text = "Unhold"
|
||||||
call.hold = true
|
call.hold = true
|
||||||
}
|
}
|
||||||
"Unhold" -> {
|
"Unhold" -> {
|
||||||
call_unhold(call.call)
|
call_unhold(call.callp)
|
||||||
v.text = "Hold"
|
v.text = "Hold"
|
||||||
call.hold = false
|
call.hold = false
|
||||||
}
|
}
|
||||||
@@ -596,14 +638,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val contentView = RemoteViews(getPackageName(), R.layout.notification)
|
val contentView = RemoteViews(getPackageName(), R.layout.notification)
|
||||||
for (i: Int in 0 .. 3) {
|
for (i: Int in 0 .. 3) {
|
||||||
val resID = resources.getIdentifier("status$i", "id", packageName);
|
val resID = resources.getIdentifier("status$i", "id", packageName);
|
||||||
if (i < accounts.size) {
|
if (i < images.size) {
|
||||||
contentView.setImageViewResource(resID, images[i])
|
contentView.setImageViewResource(resID, images[i])
|
||||||
contentView.setViewVisibility(resID, View.VISIBLE)
|
contentView.setViewVisibility(resID, View.VISIBLE)
|
||||||
} else {
|
} else {
|
||||||
contentView.setViewVisibility(resID, View.INVISIBLE)
|
contentView.setViewVisibility(resID, View.INVISIBLE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (accounts.size > 4)
|
if (images.size > 4)
|
||||||
contentView.setViewVisibility(R.id.etc, View.VISIBLE)
|
contentView.setViewVisibility(R.id.etc, View.VISIBLE)
|
||||||
else
|
else
|
||||||
contentView.setViewVisibility(R.id.etc, View.INVISIBLE)
|
contentView.setViewVisibility(R.id.etc, View.INVISIBLE)
|
||||||
@@ -613,63 +655,70 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
fun addAccount(ua: String) {
|
fun addAccount(ua: String) {
|
||||||
val aor = ua_aor(ua)
|
val userAgent = UserAgent(ua)
|
||||||
Log.d("Baresip", "Adding account $ua with AoR $aor")
|
uas.add(userAgent)
|
||||||
accounts.add(Account(ua, aor, ua_mediaenc(ua),""))
|
|
||||||
images.add(R.drawable.dot_yellow)
|
images.add(R.drawable.dot_yellow)
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
accountAdapter.notifyDataSetChanged()
|
uaAdapter.notifyDataSetChanged()
|
||||||
updateNotification()
|
updateNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
private fun updateStatus(event: String, ua: String, call: String) {
|
private fun updateStatus(event: String, uap: String, callp: String) {
|
||||||
|
|
||||||
val aor = ua_aor(ua)
|
val ua = UserAgent.find(uas, uap)
|
||||||
|
if (ua == null) {
|
||||||
|
Log.e("Baresip", "Update status did not find ua $uap")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val aor = ua.aor
|
||||||
|
val acc = ua.account
|
||||||
val ev = event.split(",")
|
val ev = event.split(",")
|
||||||
|
|
||||||
Log.d("Baresip", "Handling event ${ev[0]} for $ua/$call/$aor")
|
Log.d("Baresip", "Handling event ${ev[0]} for $uap/$callp/$aor")
|
||||||
|
|
||||||
for (account_index in accounts.indices) {
|
for (account_index in uas.indices) {
|
||||||
if (accounts[account_index].aoR == aor) {
|
if (uas[account_index].aor == aor) {
|
||||||
Log.d("Baresip", "Found AoR at index $account_index")
|
Log.d("Baresip", "Found AoR at index $account_index")
|
||||||
when (ev[0]) {
|
when (ev[0]) {
|
||||||
"registering", "unregistering" -> {
|
"registering", "unregistering" -> {
|
||||||
}
|
}
|
||||||
"registered" -> {
|
"registered" -> {
|
||||||
Log.d("Baresip", "Setting status to green")
|
Log.d("Baresip", "Setting status to green")
|
||||||
accounts[account_index].status = "OK"
|
|
||||||
images[account_index] = R.drawable.dot_green
|
images[account_index] = R.drawable.dot_green
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
accountAdapter.notifyDataSetChanged()
|
uaAdapter.notifyDataSetChanged()
|
||||||
updateNotification()
|
updateNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"registering failed" -> {
|
"registering failed" -> {
|
||||||
Log.d("Baresip", "Setting status to red")
|
Log.d("Baresip", "Setting status to red")
|
||||||
accounts[account_index].status = "FAIL"
|
|
||||||
images[account_index] = R.drawable.dot_red
|
images[account_index] = R.drawable.dot_red
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
accountAdapter.notifyDataSetChanged()
|
uaAdapter.notifyDataSetChanged()
|
||||||
updateNotification()
|
updateNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"call ringing" -> {
|
"call ringing" -> {
|
||||||
}
|
}
|
||||||
"call established" -> {
|
"call established" -> {
|
||||||
val out_index = Call.callIndex(callsOut, ua, call)
|
val call = Call.find(calls, callp)
|
||||||
if (out_index != -1) {
|
if (call == null) {
|
||||||
Log.d("Baresip", "Outbound call $call established")
|
Log.e("Baresip", "Established call $callp not found")
|
||||||
callsOut[out_index].status = "Hangup"
|
return
|
||||||
callsOut[out_index].hold = false
|
}
|
||||||
callsOut[out_index].security = R.drawable.box_red
|
if (call.dir == "out") {
|
||||||
|
Log.d("Baresip", "Outbound call $callp established")
|
||||||
|
call.status = "Hangup"
|
||||||
|
call.hold = false
|
||||||
|
call.security = R.drawable.box_red
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
callButton.text = "Hangup"
|
callButton.text = "Hangup"
|
||||||
holdButton.text = "Hold"
|
holdButton.text = "Hold"
|
||||||
holdButton.visibility = View.VISIBLE
|
holdButton.visibility = View.VISIBLE
|
||||||
if (ua_mediaenc(ua) == "") {
|
if (acc.mediaenc == "") {
|
||||||
securityButton.visibility = View.INVISIBLE
|
securityButton.visibility = View.INVISIBLE
|
||||||
} else {
|
} else {
|
||||||
securityButton.setImageResource(R.drawable.box_red)
|
securityButton.setImageResource(R.drawable.box_red)
|
||||||
@@ -680,36 +729,34 @@ class MainActivity : AppCompatActivity() {
|
|||||||
dtmf.hint = "DTMF"
|
dtmf.hint = "DTMF"
|
||||||
dtmf.visibility = View.VISIBLE
|
dtmf.visibility = View.VISIBLE
|
||||||
dtmf.requestFocus()
|
dtmf.requestFocus()
|
||||||
dtmf.addTextChangedListener(callsOut[out_index].dtmfWatcher)
|
dtmf.addTextChangedListener(call.dtmfWatcher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
HistoryActivity.History.add(History(aor, call.peerURI, "out",
|
||||||
"out", true))
|
true))
|
||||||
|
call.hasHistory = true
|
||||||
} else {
|
} else {
|
||||||
val in_index = Call.callIndex(callsIn, ua, call)
|
Log.d("Baresip", "Inbound call $callp established")
|
||||||
if (in_index != -1) {
|
call.status = "Answer"
|
||||||
Log.d("Baresip", "Inbound call $call established")
|
call.security = R.drawable.box_red
|
||||||
callsIn[in_index].status = "Answer"
|
|
||||||
callsIn[in_index].security = R.drawable.box_red
|
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
if (ua_mediaenc(ua) != "") {
|
if (acc.mediaenc != "") {
|
||||||
var view_id = (in_index + 1) * 10 + 3
|
val inIndex = Call.index(calls, call, "in")
|
||||||
|
var view_id = (inIndex + 1) * 10 + 3
|
||||||
val securityButton = findViewById(view_id) as ImageButton
|
val securityButton = findViewById(view_id) as ImageButton
|
||||||
securityButton.setImageResource(R.drawable.box_red)
|
securityButton.setImageResource(R.drawable.box_red)
|
||||||
securityButton.tag = "red"
|
securityButton.tag = "red"
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
view_id = (in_index + 1) * 10 + 5
|
view_id = (inIndex + 1) * 10 + 5
|
||||||
val rejectButton = findViewById(view_id) as Button
|
val rejectButton = findViewById(view_id) as Button
|
||||||
rejectButton.text = "Hold"
|
rejectButton.text = "Hold"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
HistoryActivity.History.add(History(aor, call.peerURI, "in",
|
||||||
"in", true))
|
true))
|
||||||
} else {
|
call.hasHistory = true
|
||||||
Log.e("Baresip", "Unknown call $ua/$call established")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||||
am.isSpeakerphoneOn = false
|
am.isSpeakerphoneOn = false
|
||||||
@@ -720,78 +767,68 @@ class MainActivity : AppCompatActivity() {
|
|||||||
HistoryActivity.aorRemoveHistory(aor)
|
HistoryActivity.aorRemoveHistory(aor)
|
||||||
}
|
}
|
||||||
"call incoming" -> {
|
"call incoming" -> {
|
||||||
val peer_uri = call_peeruri(call)
|
val peer_uri = call_peeruri(callp)
|
||||||
Log.d("Baresip", "Incoming call " + ua + "/" + call + "/" +
|
Log.d("Baresip", "Incoming call $uap/$callp/$peer_uri")
|
||||||
peer_uri)
|
val new_call = Call(callp, ua, peer_uri, "in", "Answer", null)
|
||||||
val new_call = Call(ua, call, peer_uri, "Answer", null)
|
calls.add(new_call)
|
||||||
callsIn.add(new_call)
|
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
addCallViews(ua, new_call, callsIn.size * 10)
|
addCallViews(ua, new_call, Call.calls(calls, "in").size * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
am.mode = AudioManager.MODE_RINGTONE
|
am.mode = AudioManager.MODE_RINGTONE
|
||||||
// am.isSpeakerphoneOn = true
|
// am.isSpeakerphoneOn = true
|
||||||
}
|
}
|
||||||
"call verify" -> {
|
"call verify" -> {
|
||||||
|
val call = Call.find(calls, callp)
|
||||||
|
if (call == null) {
|
||||||
|
Log.e("Baresip", "Call $callp to be verified is not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
val verifyDialog = AlertDialog.Builder(this)
|
val verifyDialog = AlertDialog.Builder(this)
|
||||||
verifyDialog.setTitle("Verify")
|
verifyDialog.setTitle("Verify")
|
||||||
verifyDialog.setMessage("Do you want to verify SAS <${ev[1]}> <${ev[2]}>?")
|
verifyDialog.setMessage("Do you want to verify SAS <${ev[1]}> <${ev[2]}>?")
|
||||||
verifyDialog.setPositiveButton("Yes") { dialog, _ ->
|
verifyDialog.setPositiveButton("Yes") { dialog, _ ->
|
||||||
val security: Int
|
val security: Int
|
||||||
if (cmd_exec("zrtp_verify ${ev[3]}") != 0) {
|
if (Utils.cmd_exec("zrtp_verify ${ev[3]}") != 0) {
|
||||||
Log.w("Baresip", "Command 'zrtp_verify ${ev[3]}' failed")
|
Log.w("Baresip", "Command 'zrtp_verify ${ev[3]}' failed")
|
||||||
security = R.drawable.box_yellow
|
security = R.drawable.box_yellow
|
||||||
} else {
|
} else {
|
||||||
security = R.drawable.box_green
|
security = R.drawable.box_green
|
||||||
}
|
}
|
||||||
var index = Call.callIndex(callsOut, ua, call)
|
call.security = security
|
||||||
if (index != -1) {
|
call.zid = ev[3]
|
||||||
callsOut[index].security = security
|
if (call.dir == "out") {
|
||||||
callsOut[index].zid = ev[3]
|
|
||||||
securityButton.setImageResource(security)
|
securityButton.setImageResource(security)
|
||||||
Utils.setSecurityButtonTag(securityButton, security)
|
setSecurityButtonTag(securityButton, security)
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
index = Call.callIndex(callsIn, ua, call)
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
if (index != -1) {
|
val view_id = (Call.index(calls, call, "in") + 1) * 10 + 3
|
||||||
callsIn[index].security = security
|
|
||||||
callsIn[index].zid = ev[3]
|
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
|
||||||
val view_id = (index + 1) * 10 + 3
|
|
||||||
val securityButton = layout.findViewById(view_id) as ImageButton
|
val securityButton = layout.findViewById(view_id) as ImageButton
|
||||||
securityButton.setImageResource(security)
|
securityButton.setImageResource(security)
|
||||||
Utils.setSecurityButtonTag(securityButton, security)
|
setSecurityButtonTag(securityButton, security)
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
verifyDialog.setNegativeButton("No") { dialog, _ ->
|
verifyDialog.setNegativeButton("No") { dialog, _ ->
|
||||||
var index = Call.callIndex(callsOut, ua, call)
|
call.security = R.drawable.box_yellow
|
||||||
if (index >= 0) {
|
call.zid = ev[3]
|
||||||
callsOut[index].security = R.drawable.box_yellow
|
if (call.dir == "out") {
|
||||||
callsOut[index].zid = ev[3]
|
|
||||||
securityButton.setImageResource(R.drawable.box_yellow)
|
securityButton.setImageResource(R.drawable.box_yellow)
|
||||||
securityButton.tag = "yellow"
|
securityButton.tag = "yellow"
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
index = Call.callIndex(callsIn, ua, call)
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
if (index != -1) {
|
val view_id = (Call.index(calls, call, "in") + 1) * 10 + 3
|
||||||
callsIn[index].security = R.drawable.box_yellow
|
|
||||||
callsIn[index].zid = ev[3]
|
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
|
||||||
val view_id = (index + 1) * 10 + 3
|
|
||||||
val securityButton = layout.findViewById(view_id) as ImageButton
|
val securityButton = layout.findViewById(view_id) as ImageButton
|
||||||
securityButton.setImageResource(R.drawable.box_yellow)
|
securityButton.setImageResource(R.drawable.box_yellow)
|
||||||
securityButton.tag = "yellow"
|
securityButton.tag = "yellow"
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.e("Baresip", "Unknown call $ua/$call to verify")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
@@ -799,46 +836,48 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"call verified" -> {
|
"call verified" -> {
|
||||||
val out_index = Call.callIndex(callsOut, ua, call)
|
val call = Call.find(calls, callp)
|
||||||
if (out_index != -1) {
|
if (call == null) {
|
||||||
callsOut[out_index].security = R.drawable.box_green
|
Log.e("Baresip", "Call $callp that is verified is not found")
|
||||||
callsOut[out_index].zid = ev[1]
|
return
|
||||||
|
}
|
||||||
|
call.security = R.drawable.box_green
|
||||||
|
call.zid = ev[1]
|
||||||
|
if (call.dir == "out") {
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
securityButton.setImageResource(R.drawable.box_green)
|
securityButton.setImageResource(R.drawable.box_green)
|
||||||
securityButton.tag = "green"
|
securityButton.tag = "green"
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val in_index = Call.callIndex(callsIn, ua, call)
|
|
||||||
if (in_index != -1) {
|
|
||||||
callsIn[in_index].security = R.drawable.box_green
|
|
||||||
callsIn[in_index].zid = ev[1]
|
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
val view_id = (in_index + 1) * 10 + 3
|
val view_id = (Call.index(calls, call, "in") + 1) * 10 + 3
|
||||||
val securityButton = layout.findViewById(view_id) as ImageButton
|
val securityButton = layout.findViewById(view_id) as ImageButton
|
||||||
securityButton.setImageResource(R.drawable.box_green)
|
securityButton.setImageResource(R.drawable.box_green)
|
||||||
securityButton.tag = "green"
|
securityButton.tag = "green"
|
||||||
securityButton.visibility = View.VISIBLE
|
securityButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.e("Baresip", "Unknown call $ua/$call verified")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"call closed" -> {
|
"call closed" -> {
|
||||||
val in_index = Call.callIndex(callsIn, ua, call)
|
val call = Call.find(calls, callp)
|
||||||
if (in_index != -1) {
|
if (call == null) {
|
||||||
Log.d("Baresip", "Removing inbound call " + ua + "/" +
|
Log.e("Baresip", "Call $callp that is closed is not found")
|
||||||
call + "/" + callsIn[in_index].peerURI)
|
return
|
||||||
val view_id = (in_index + 1) * 10
|
}
|
||||||
val remove_count = callsIn.size - in_index
|
if (call.dir == "in") {
|
||||||
callsIn.removeAt(in_index)
|
Log.d("Baresip", "Removing inbound call $uap / $callp / " +
|
||||||
|
call.peerURI)
|
||||||
|
val inIndex = Call.index(calls, call, "in")
|
||||||
|
val view_id = (inIndex + 1) * 10
|
||||||
|
val remove_count = Call.calls(calls, "in").size - inIndex
|
||||||
|
calls.removeAt(Call.index(calls, call, ""))
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
if (callButton.text == "Call") {
|
if (callButton.text == "Call") {
|
||||||
holdButton.text = "History"
|
holdButton.text = "History"
|
||||||
holdButton.visibility = View.VISIBLE
|
holdButton.visibility = View.VISIBLE
|
||||||
@@ -847,24 +886,23 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val caller_heading = layout.findViewById(view_id)
|
val caller_heading = layout.findViewById(view_id)
|
||||||
val view_index = layout.indexOfChild(caller_heading)
|
val view_index = layout.indexOfChild(caller_heading)
|
||||||
layout.removeViews(view_index, 4 * remove_count)
|
layout.removeViews(view_index, 4 * remove_count)
|
||||||
for (i in in_index until callsIn.size) {
|
val callsIn = Call.calls(calls, "in")
|
||||||
|
for (i in inIndex until callsIn.size) {
|
||||||
this@MainActivity.addCallViews(ua, callsIn[i], (i + 1) * 10)
|
this@MainActivity.addCallViews(ua, callsIn[i], (i + 1) * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!HistoryActivity.callHasHistory(ua, call)) {
|
if (!call.hasHistory) {
|
||||||
if (HistoryActivity.aorHistory(aor) > HISTORY_SIZE)
|
if (HistoryActivity.aorHistory(aor) > HISTORY_SIZE)
|
||||||
HistoryActivity.aorRemoveHistory(aor)
|
HistoryActivity.aorRemoveHistory(aor)
|
||||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
HistoryActivity.History.add(History(aor, call.peerURI,
|
||||||
"in", false))
|
"in", false))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val out_index = Call.callIndex(callsOut, ua, call)
|
Log.d("Baresip", "Removing outgoing call $uap / $callp / " +
|
||||||
if (out_index != -1) {
|
call.peerURI)
|
||||||
Log.d("Baresip", "Removing outgoing call " + ua + "/" +
|
|
||||||
call + "/" + callsOut[out_index].peerURI)
|
|
||||||
this@MainActivity.runOnUiThread {
|
this@MainActivity.runOnUiThread {
|
||||||
if (ua == accounts[aorSpinner.selectedItemPosition].ua) {
|
if (ua == uas[aorSpinner.selectedItemPosition]) {
|
||||||
callButton.text = "Call"
|
callButton.text = "Call"
|
||||||
callButton.isEnabled = true
|
callButton.isEnabled = true
|
||||||
callee.setText("")
|
callee.setText("")
|
||||||
@@ -875,24 +913,19 @@ class MainActivity : AppCompatActivity() {
|
|||||||
imm.hideSoftInputFromWindow(dtmf.getWindowToken(), 0)
|
imm.hideSoftInputFromWindow(dtmf.getWindowToken(), 0)
|
||||||
}
|
}
|
||||||
securityButton.visibility = View.INVISIBLE
|
securityButton.visibility = View.INVISIBLE
|
||||||
dtmf.removeTextChangedListener(callsOut[out_index].dtmfWatcher)
|
dtmf.removeTextChangedListener(call.dtmfWatcher)
|
||||||
dtmf.visibility = View.INVISIBLE
|
dtmf.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
callsOut.removeAt(out_index)
|
calls.removeAt(Call.index(calls, call, ""))
|
||||||
}
|
}
|
||||||
if (!HistoryActivity.callHasHistory(ua, call)) {
|
if (!call.hasHistory) {
|
||||||
if (HistoryActivity.aorHistory(aor) > HISTORY_SIZE)
|
if (HistoryActivity.aorHistory(aor) > HISTORY_SIZE)
|
||||||
HistoryActivity.aorRemoveHistory(aor)
|
HistoryActivity.aorRemoveHistory(aor)
|
||||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
HistoryActivity.History.add(History(aor, call.peerURI,
|
||||||
"out", false))
|
"out", false))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.e("Baresip", "Unknown call " + ua + "/" + call +
|
|
||||||
" closed")
|
|
||||||
}
|
}
|
||||||
}
|
if (calls.size == 0) am.mode = AudioManager.MODE_NORMAL
|
||||||
if ((callsIn.size == 0) && (callsOut.size == 0))
|
|
||||||
am.mode = AudioManager.MODE_NORMAL
|
|
||||||
}
|
}
|
||||||
else -> Log.d("Baresip", "Unknown event '${ev[0]}'")
|
else -> Log.d("Baresip", "Unknown event '${ev[0]}'")
|
||||||
}
|
}
|
||||||
@@ -900,33 +933,56 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun copyAssetToFile(context: Context, asset: String, path: String) {
|
||||||
|
try {
|
||||||
|
val `is` = context.assets.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 setSecurityButtonTag(button: ImageButton, security: Int) {
|
||||||
|
when (security) {
|
||||||
|
R.drawable.box_red -> { button.tag = "red" }
|
||||||
|
R.drawable.box_yellow -> { button.tag = "yellow" }
|
||||||
|
R.drawable.box_green -> { button.tag = "green" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
external fun baresipStart(path: String)
|
external fun baresipStart(path: String)
|
||||||
external fun baresipStop()
|
external fun baresipStop()
|
||||||
external fun call_peeruri(call: String): String
|
|
||||||
external fun ua_aor(ua: String): String
|
|
||||||
external fun ua_mediaenc(ua: String): String
|
|
||||||
external fun ua_connect(ua: String, peer_uri: String): String
|
external fun ua_connect(ua: String, peer_uri: String): String
|
||||||
external fun ua_answer(ua: String, call: String)
|
external fun ua_answer(ua: String, call: String)
|
||||||
external fun ua_hangup(ua: String, call: String, code: Int, reason: String)
|
external fun ua_hangup(ua: String, call: String, code: Int, reason: String)
|
||||||
|
external fun call_peeruri(call: String): String
|
||||||
external fun call_hold(call: String): Int
|
external fun call_hold(call: String): Int
|
||||||
external fun call_unhold(call: String): Int
|
external fun call_unhold(call: String): Int
|
||||||
external fun call_send_digit(call: String, digit: Char): Int
|
external fun call_send_digit(call: String, digit: Char): Int
|
||||||
external fun cmd_exec(cmd: String): Int
|
|
||||||
external fun reload_config(): Int
|
external fun reload_config(): Int
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal var running: Boolean = false
|
internal var running: Boolean = false
|
||||||
internal var accounts = ArrayList<Account>()
|
var uas = ArrayList<UserAgent>()
|
||||||
internal var images = ArrayList<Int>()
|
internal var images = ArrayList<Int>()
|
||||||
internal var callsIn = ArrayList<Call>()
|
internal var calls = ArrayList<Call>()
|
||||||
internal var callsOut = ArrayList<Call>()
|
var filesPath = ""
|
||||||
|
|
||||||
const val EDIT_ACCOUNTS_CODE = 1
|
const val ACCOUNTS_CODE = 1
|
||||||
const val EDIT_CONTACTS_CODE = 2
|
const val EDIT_CONTACTS_CODE = 2
|
||||||
const val EDIT_CONFIG_CODE = 3
|
const val EDIT_CONFIG_CODE = 3
|
||||||
const val HISTORY_CODE = 4
|
const val HISTORY_CODE = 4
|
||||||
const val ABOUT_CODE = 5
|
const val ABOUT_CODE = 5
|
||||||
|
const val ACCOUNT_CODE = 6
|
||||||
|
|
||||||
const val RECORD_AUDIO_PERMISSION = 1
|
const val RECORD_AUDIO_PERMISSION = 1
|
||||||
const val HISTORY_SIZE = 100
|
const val HISTORY_SIZE = 100
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
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 UaSpinnerAdapter(private val cxt: Context, private val uas: ArrayList<UserAgent>,
|
||||||
|
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 = uas[position].aor.replace("sip:", "")
|
||||||
|
textView.textSize = 17f
|
||||||
|
val imageView = row.findViewById(R.id.spinnerImage) as ImageView
|
||||||
|
imageView.setImageResource(images[position])
|
||||||
|
return row
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
class UserAgent (val uap: String) {
|
||||||
|
|
||||||
|
val account = Account(ua_account(uap))
|
||||||
|
val aor = ua_aor(uap)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
external fun ua_alloc(uri: String): Int
|
||||||
|
external fun ua_destroy(uri: String)
|
||||||
|
external fun ua_register(ua: String): Int
|
||||||
|
external fun ua_isregistered(ua: String): Boolean
|
||||||
|
external fun ua_unregister(ua: String)
|
||||||
|
|
||||||
|
fun userAgents(): ArrayList<UserAgent> {
|
||||||
|
val res = ArrayList<UserAgent>()
|
||||||
|
for (ua in MainActivity.uas) {
|
||||||
|
res.add(ua)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fun find(uas: ArrayList<UserAgent>, uap: String): UserAgent? {
|
||||||
|
for (u in uas) {
|
||||||
|
if (u.uap == uap) return u
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
external fun ua_account(ua: String): String
|
||||||
|
external fun ua_aor(ua: String): String
|
||||||
|
|
||||||
@@ -3,28 +3,11 @@ package com.tutpro.baresip
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.ImageButton
|
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
|
||||||
object Utils {
|
object Utils {
|
||||||
|
|
||||||
fun copyAssetToFile(context: Context, asset: String, path: String) {
|
|
||||||
try {
|
|
||||||
val `is` = context.assets.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())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getFileContents(file: File): String {
|
fun getFileContents(file: File): String {
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
Log.e("Baresip", "Failed to find file: " + file.path)
|
Log.e("Baresip", "Failed to find file: " + file.path)
|
||||||
@@ -89,46 +72,51 @@ object Utils {
|
|||||||
return uri.substringAfter(":").substringBefore("@")
|
return uri.substringAfter(":").substringBefore("@")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSecurityButtonTag(button: ImageButton, security: Int) {
|
fun checkUserID(id: String): Boolean {
|
||||||
when (security) {
|
return Regex("^[a-zA-Z]([._-]|[a-zA-Z0-9]){1,49}\$").matches(id)
|
||||||
R.drawable.box_red -> { button.tag = "red" }
|
|
||||||
R.drawable.box_yellow -> { button.tag = "yellow" }
|
|
||||||
R.drawable.box_green -> { button.tag = "green" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSecurityButtonOnClickListener(context: Context, button: ImageButton, call: Call) {
|
fun checkTelNo(no: String): Boolean {
|
||||||
button.setOnClickListener {
|
return Regex("^[+]?[0-9]{1,16}\$").matches(no)
|
||||||
when (button.tag) {
|
|
||||||
"red" -> {
|
|
||||||
Utils.alertView(context, "Alert", "This call is NOT secure!")
|
|
||||||
}
|
}
|
||||||
"yellow" -> {
|
|
||||||
Utils.alertView(context, "Alert",
|
fun checkIP(ip: String): Boolean {
|
||||||
"This call is SECURE, but peer is NOT verified!")
|
return Regex("^(([0-1]?[0-9]{1,2}\\.)|(2[0-4][0-9]\\.)|(25[0-5]\\.)){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))/$").matches(ip)
|
||||||
}
|
}
|
||||||
"green" -> {
|
|
||||||
val unverifyDialog = AlertDialog.Builder(context)
|
fun checkDomain(domain: String): Boolean {
|
||||||
unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " +
|
val parts = domain.split(".")
|
||||||
"Do you want to unverify the peer?")
|
for (p in parts) {
|
||||||
unverifyDialog.setPositiveButton("Unverify") { dialog, _ ->
|
if (p.length == 0 || p.endsWith("-") || !Regex("^[a-zA-z]([-]|[a-zA-Z0-9])+\$").matches(p))
|
||||||
if (cmd_exec("zrtp_unverify " + call.zid) != 0) {
|
return false
|
||||||
Log.w("Baresip", "Command 'zrtp_unverify ${call.zid}' failed")
|
|
||||||
} else {
|
|
||||||
button.setImageResource(R.drawable.box_yellow)
|
|
||||||
button.tag = "yellow"
|
|
||||||
}
|
}
|
||||||
dialog.dismiss()
|
return true
|
||||||
}
|
}
|
||||||
unverifyDialog.setNegativeButton("No") { dialog, _ ->
|
|
||||||
dialog.dismiss()
|
fun checkPrintASCII(s: String): Boolean {
|
||||||
}
|
if (s == "") return true
|
||||||
unverifyDialog.create().show()
|
val printASCIIRegex = Regex("^[ -~]*\$")
|
||||||
|
return printASCIIRegex.matches(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun checkUint(s: String): Boolean {
|
||||||
|
val uintRegex = Regex("^[0-9]+\$")
|
||||||
|
return uintRegex.matches(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun implode(list: List<String>, sep: String): String {
|
||||||
|
var res = ""
|
||||||
|
for (s in list) {
|
||||||
|
if (res == "")
|
||||||
|
res = s
|
||||||
|
else
|
||||||
|
res = res + sep + s
|
||||||
}
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
external fun cmd_exec(cmd: String): Int
|
external fun cmd_exec(cmd: String): Int
|
||||||
|
external fun uri_decode(uri: String): Boolean
|
||||||
|
external fun audio_codecs(): String
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 509 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#ffffff" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/accountRow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/aor"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:layout_marginBottom="6dp">
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/action"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:icon="@android:drawable/ic_menu_delete"
|
||||||
|
android:scaleType="centerCrop" >
|
||||||
|
</ImageButton>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/AccountView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="24dp" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/DisplayNameTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:text="Display Name" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/DisplayName"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Your Name"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/AuthUserTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:text="Authentication Username" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/AuthUser"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="User ID"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/AuthPassTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:text="Authentication Password" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/AuthPass"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Password"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/OutboundProxyTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:text="Outbound Proxies" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/Outbound1"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="SIP URI of Proxy Server"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/Outbound2"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="SIP URI of another Proxy Server"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/RegIntTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:text="Registration Interval (sec)" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/RegInt"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/AudioCodecsTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:text="Audio Codecs" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/CodecSpinners"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/MediaEncTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:text="Media Encryption" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/mediaEncSpinner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:popupBackground="@drawable/spinner_background" >
|
||||||
|
</Spinner>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
tools:context="com.tutpro.baresip.AccountsActivity">
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/accounts"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/newAor"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:hint="SIP URI user@domain" >
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/addAccount"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_marginLeft="6dp"
|
||||||
|
android:src="@drawable/action_add"
|
||||||
|
android:scaleType="centerCrop" >
|
||||||
|
</ImageButton>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/historyRow"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:layout_marginBottom="0dp"
|
android:layout_marginBottom="0dp"
|
||||||
|
|||||||
Reference in New Issue
Block a user