introduced support for sending and receiving messages
This commit is contained in:
@ -9,14 +9,18 @@
|
|||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
||||||
<uses-permission android:name="android.permission.CALL_PHONE" />
|
<uses-permission android:name="android.permission.CALL_PHONE" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.telephony"
|
android:name="android.hardware.telephony"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.camera"
|
android:name="android.hardware.camera"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
@ -36,9 +40,10 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher"
|
android:roundIcon="@mipmap/ic_launcher"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity android:name=".MainActivity"
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
android:launchMode="singleTask" >
|
android:launchMode="singleTask">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@ -47,7 +52,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".AccountsActivity"
|
android:name=".AccountsActivity"
|
||||||
android:label="Accounts"
|
android:label="Accounts"
|
||||||
android:parentActivityName=".MainActivity" >
|
android:parentActivityName=".MainActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.tutpro.baresip.MainActivity" />
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
@ -64,8 +69,8 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ContactsActivity"
|
android:name=".ContactsActivity"
|
||||||
android:label="Contacts"
|
android:label="Contacts"
|
||||||
android:windowSoftInputMode="adjustPan"
|
android:parentActivityName=".MainActivity"
|
||||||
android:parentActivityName=".MainActivity" >
|
android:windowSoftInputMode="adjustPan">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.tutpro.baresip.MainActivity" />
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
@ -74,7 +79,7 @@
|
|||||||
android:name=".ContactActivity"
|
android:name=".ContactActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
android:label="Contact"
|
android:label="Contact"
|
||||||
android:parentActivityName=".MainActivity" >
|
android:parentActivityName=".MainActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.tutpro.baresip.MainActivity" />
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
@ -95,6 +100,22 @@
|
|||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.tutpro.baresip.MainActivity" />
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".MessagesActivity"
|
||||||
|
android:label="Message History"
|
||||||
|
android:parentActivityName=".MainActivity">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".MessageActivity"
|
||||||
|
android:label="Message"
|
||||||
|
android:parentActivityName=".MessagesActivity" >
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".AboutActivity"
|
android:name=".AboutActivity"
|
||||||
android:label="About"
|
android:label="About"
|
||||||
@ -104,21 +125,21 @@
|
|||||||
android:value="com.tutpro.baresip.MainActivity" />
|
android:value="com.tutpro.baresip.MainActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service android:name=".BaresipService"
|
<service
|
||||||
|
android:name=".BaresipService"
|
||||||
android:enabled="true" >
|
android:enabled="true" >
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
|
android:name=".RunOnStartup"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:name="com.tutpro.baresip.RunOnStartup"
|
|
||||||
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="com.tutpro.baresip.Restart" />
|
<action android:name="com.tutpro.baresip.Restart" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@ -166,7 +166,7 @@ static void ua_event_handler(struct ua *ua, enum ua_event ev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jmethodID statusId = (*env)->GetMethodID(env, pctx->mainActivityClz,
|
jmethodID statusId = (*env)->GetMethodID(env, pctx->mainActivityClz,
|
||||||
"updateStatus",
|
"uaEvent",
|
||||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||||
sprintf(ua_buf, "%lu", (unsigned long)ua);
|
sprintf(ua_buf, "%lu", (unsigned long)ua);
|
||||||
jstring javaUA = (*env)->NewStringUTF(env, ua_buf);
|
jstring javaUA = (*env)->NewStringUTF(env, ua_buf);
|
||||||
@ -180,16 +180,71 @@ static void ua_event_handler(struct ua *ua, enum ua_event ev,
|
|||||||
(*env)->DeleteLocalRef(env, javaEvent);
|
(*env)->DeleteLocalRef(env, javaEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void message_handler(const struct pl *peer, const struct pl *ctype,
|
static void message_handler(struct ua *ua, const struct pl *peer, const struct pl *ctype,
|
||||||
struct mbuf *body, void *arg)
|
struct mbuf *body, void *arg)
|
||||||
{
|
{
|
||||||
(void)ctype;
|
(void)ctype;
|
||||||
(void)arg;
|
(void)arg;
|
||||||
|
char ua_buf[32];
|
||||||
|
char peer_buf[256];
|
||||||
|
char msg_buf[1024];
|
||||||
|
char utf_buf[2048];
|
||||||
|
char *in, *out;
|
||||||
|
int size;
|
||||||
|
|
||||||
LOGD("got message '%.*s' from peer '%.*s'", mbuf_get_left(body), mbuf_buf(body),
|
LOGD("got message '%.*s' from peer '%.*s'", mbuf_get_left(body), mbuf_buf(body),
|
||||||
peer->l, peer->p);
|
peer->l, peer->p);
|
||||||
|
|
||||||
(void)play_file(NULL, baresip_player(), "message.wav", 0);
|
UpdateContext *pctx = (UpdateContext*)(&g_ctx);
|
||||||
|
JavaVM *javaVM = pctx->javaVM;
|
||||||
|
JNIEnv *env;
|
||||||
|
jint res = (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_6);
|
||||||
|
if (res != JNI_OK) {
|
||||||
|
res = (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
|
||||||
|
if (JNI_OK != res) {
|
||||||
|
LOGE("Failed to AttachCurrentThread, ErrorCode = %d", res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jmethodID methodId = (*env)->GetMethodID(env, pctx->mainActivityClz,
|
||||||
|
"messageEvent",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/String;[B)V");
|
||||||
|
sprintf(ua_buf, "%lu", (unsigned long)ua);
|
||||||
|
jstring javaUA = (*env)->NewStringUTF(env, ua_buf);
|
||||||
|
sprintf(peer_buf, "%.*s", peer->l, peer->p);
|
||||||
|
jstring javaPeer = (*env)->NewStringUTF(env, peer_buf);
|
||||||
|
jbyteArray javaMsg;
|
||||||
|
size = mbuf_get_left(body);
|
||||||
|
javaMsg = (*env)->NewByteArray(env, size);
|
||||||
|
if ((*env)->GetArrayLength(env, javaMsg) != size) {
|
||||||
|
(*env)->DeleteLocalRef(env, javaMsg);
|
||||||
|
javaMsg = (*env)->NewByteArray(env, size);
|
||||||
|
}
|
||||||
|
void *temp = (*env)->GetPrimitiveArrayCritical(env, (jarray)javaMsg, 0);
|
||||||
|
memcpy(temp, mbuf_buf(body), size);
|
||||||
|
(*env)->ReleasePrimitiveArrayCritical(env, javaMsg, temp, 0);
|
||||||
|
LOGD("sending message %s/%s/%.*s\n", ua_buf, peer_buf, size, mbuf_buf(body));
|
||||||
|
(*env)->CallVoidMethod(env, pctx->mainActivityObj, methodId, javaUA, javaPeer, javaMsg);
|
||||||
|
(*env)->DeleteLocalRef(env, javaUA);
|
||||||
|
(*env)->DeleteLocalRef(env, javaPeer);
|
||||||
|
(*env)->DeleteLocalRef(env, javaMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_resp_handler(int err, const struct sip_msg *msg, void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
LOGD("received message response %u\n", msg->scode);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
(void)re_fprintf(stderr, " \x1b[31m%m\x1b[;m\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->scode >= 300) {
|
||||||
|
(void)re_fprintf(stderr, " \x1b[31m%u %r\x1b[;m\n",
|
||||||
|
msg->scode, &msg->reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -332,7 +387,7 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
|
|||||||
sprintf(ua_buf, "%lu", (unsigned long) ua);
|
sprintf(ua_buf, "%lu", (unsigned long) ua);
|
||||||
jstring javaUA = (*env)->NewStringUTF(env, ua_buf);
|
jstring javaUA = (*env)->NewStringUTF(env, ua_buf);
|
||||||
LOGD("adding UA for AoR %s/%s\n", ua_aor(ua), ua_buf);
|
LOGD("adding UA for AoR %s/%s\n", ua_aor(ua), ua_buf);
|
||||||
jmethodID accountId = (*env)->GetMethodID(env, pctx->mainActivityClz, "addUA",
|
jmethodID accountId = (*env)->GetMethodID(env, pctx->mainActivityClz, "uaAdd",
|
||||||
"(Ljava/lang/String;)V");
|
"(Ljava/lang/String;)V");
|
||||||
(*env)->CallVoidMethod(env, pctx->mainActivityObj, accountId, javaUA);
|
(*env)->CallVoidMethod(env, pctx->mainActivityObj, accountId, javaUA);
|
||||||
(*env)->DeleteLocalRef(env, javaUA);
|
(*env)->DeleteLocalRef(env, javaUA);
|
||||||
@ -909,6 +964,27 @@ Java_com_tutpro_baresip_MainActivity_call_1send_1digit(JNIEnv *env, jobject thiz
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_tutpro_baresip_MessageActivity_message_1send(JNIEnv *env, jobject thiz, jstring javaUA,
|
||||||
|
jstring javaPeer, jstring javaMsg) {
|
||||||
|
struct ua *ua;
|
||||||
|
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
|
||||||
|
const char *native_peer = (*env)->GetStringUTFChars(env, javaPeer, 0);
|
||||||
|
const char *native_msg = (*env)->GetStringUTFChars(env, javaMsg, 0);
|
||||||
|
|
||||||
|
LOGD("sending message from ua %s to %s\n", native_ua, native_peer);
|
||||||
|
ua = (struct ua *)strtoul(native_ua, NULL, 10);
|
||||||
|
int err = message_send(ua, native_peer, native_msg, send_resp_handler, NULL);
|
||||||
|
if (err) {
|
||||||
|
LOGW("message_send failed with error %d\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaPeer, native_peer);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, javaMsg, native_msg);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_tutpro_baresip_ContactsActivity_00024Companion_contacts_1remove(JNIEnv *env, jobject thiz) {
|
Java_com_tutpro_baresip_ContactsActivity_00024Companion_contacts_1remove(JNIEnv *env, jobject thiz) {
|
||||||
struct le *le;
|
struct le *le;
|
||||||
|
|||||||
@ -91,7 +91,7 @@ class Account(val accp: String) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findUA(aor: String): UserAgent? {
|
fun findUa(aor: String): UserAgent? {
|
||||||
for (ua in MainActivity.uas) {
|
for (ua in MainActivity.uas) {
|
||||||
if (ua.account.aor == aor) return ua
|
if (ua.account.aor == aor) return ua
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,10 @@ import java.io.ObjectInputStream
|
|||||||
import android.support.v4.content.LocalBroadcastManager
|
import android.support.v4.content.LocalBroadcastManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE
|
import android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import kotlin.experimental.and
|
||||||
|
import android.R.attr.name
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
class BaresipService: Service() {
|
class BaresipService: Service() {
|
||||||
|
|
||||||
@ -120,6 +124,21 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file = File(path, "messages")
|
||||||
|
if (file.exists()) {
|
||||||
|
try {
|
||||||
|
val fis = FileInputStream(file)
|
||||||
|
val ois = ObjectInputStream(fis)
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
MainActivity.messages = ois.readObject() as ArrayList<Message>
|
||||||
|
Log.d(LOG_TAG, "Restored ${MainActivity.messages.size} messages")
|
||||||
|
ois.close()
|
||||||
|
fis.close()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(LOG_TAG, "InputStream exception: - " + e.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ContactsActivity.generateContacts(path + "/contacts")
|
ContactsActivity.generateContacts(path + "/contacts")
|
||||||
|
|
||||||
Thread(Runnable { baresipStart(path) }).start()
|
Thread(Runnable { baresipStart(path) }).start()
|
||||||
@ -191,7 +210,7 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
fun addUA(uap: String) {
|
fun uaAdd(uap: String) {
|
||||||
Log.d(LOG_TAG, "addUA at BaresipService")
|
Log.d(LOG_TAG, "addUA at BaresipService")
|
||||||
val ua = UserAgent(uap)
|
val ua = UserAgent(uap)
|
||||||
MainActivity.uas.add(ua)
|
MainActivity.uas.add(ua)
|
||||||
@ -205,14 +224,13 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
val intent = Intent("service event")
|
val intent = Intent("service event")
|
||||||
intent.putExtra("event", "ua added")
|
intent.putExtra("event", "ua added")
|
||||||
intent.putExtra("uap", uap)
|
intent.putExtra("params", arrayListOf(uap))
|
||||||
intent.putExtra("callp", "")
|
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||||
updateStatusNotification()
|
updateStatusNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
fun updateStatus(event: String, uap: String, callp: String) {
|
fun uaEvent(event: String, uap: String, callp: String) {
|
||||||
Log.d(LOG_TAG, "updateStatus got event $event/$uap/$callp")
|
Log.d(LOG_TAG, "updateStatus got event $event/$uap/$callp")
|
||||||
if (!IS_SERVICE_RUNNING) return
|
if (!IS_SERVICE_RUNNING) return
|
||||||
val ua = UserAgent.find(MainActivity.uas, uap)
|
val ua = UserAgent.find(MainActivity.uas, uap)
|
||||||
@ -295,11 +313,76 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
val intent = Intent("service event")
|
val intent = Intent("service event")
|
||||||
intent.putExtra("event", event)
|
intent.putExtra("event", event)
|
||||||
intent.putExtra("uap", uap)
|
intent.putExtra("params", arrayListOf(uap, callp))
|
||||||
intent.putExtra("callp", callp)
|
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
fun messageEvent(uap: String, peer: String, msg: ByteArray) {
|
||||||
|
Log.d(LOG_TAG, "message event $uap/$peer")
|
||||||
|
var s = "Decoding of message failed!"
|
||||||
|
try {
|
||||||
|
s = String(msg, StandardCharsets.UTF_8)
|
||||||
|
Log.d(LOG_TAG, "UTF-8 $s")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(LOG_TAG, "UTF-8 decode failed")
|
||||||
|
}
|
||||||
|
val timeStamp = System.currentTimeMillis().toString()
|
||||||
|
if (!Utils.isVisible()) {
|
||||||
|
val cnb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
|
||||||
|
cnb.setSmallIcon(R.drawable.ic_stat)
|
||||||
|
.setColor(0x0ca1fd)
|
||||||
|
.setContentIntent(npi)
|
||||||
|
.setDefaults(Notification.DEFAULT_SOUND)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentTitle("Message from ${ContactsActivity.contactName(peer)}")
|
||||||
|
.setContentText(s)
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
cnb.setVibrate(LongArray(0))
|
||||||
|
.setVisibility(VISIBILITY_PRIVATE)
|
||||||
|
.setPriority(Notification.PRIORITY_HIGH)
|
||||||
|
}
|
||||||
|
/* val view = RemoteViews(getPackageName(), R.layout.call_notification)
|
||||||
|
view.setTextViewText(R.id.callFrom, "Call from ${Api.call_peeruri(callp)}")
|
||||||
|
cnb.setContent(view) */
|
||||||
|
val replyIntent = Intent(this, MainActivity::class.java)
|
||||||
|
replyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||||
|
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
replyIntent.putExtra("action", "reply")
|
||||||
|
replyIntent.putExtra("uap", uap)
|
||||||
|
replyIntent.putExtra("peer", peer)
|
||||||
|
val replyPendingIntent = PendingIntent.getActivity(this,
|
||||||
|
0, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
val archiveIntent = Intent(this, MainActivity::class.java)
|
||||||
|
archiveIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||||
|
Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
archiveIntent.putExtra("action", "archive")
|
||||||
|
archiveIntent.putExtra("uap", uap)
|
||||||
|
archiveIntent.putExtra("time", timeStamp)
|
||||||
|
val archivePendingIntent = PendingIntent.getActivity(this,
|
||||||
|
1, archiveIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
val deleteIntent = Intent(this, MainActivity::class.java)
|
||||||
|
deleteIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||||
|
Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
deleteIntent.putExtra("action", "delete")
|
||||||
|
deleteIntent.putExtra("uap", uap)
|
||||||
|
deleteIntent.putExtra("time", timeStamp)
|
||||||
|
val deletePendingIntent = PendingIntent.getActivity(this,
|
||||||
|
2, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
/* view.setOnClickPendingIntent(R.id.answerButton, answerPendingIntent)
|
||||||
|
view.setOnClickPendingIntent(R.id.rejectButton, rejectPendingIntent)
|
||||||
|
cnb.setCustomBigContentView(view) */
|
||||||
|
cnb.addAction(R.drawable.ic_stat, "Reply", replyPendingIntent)
|
||||||
|
cnb.addAction(R.drawable.ic_stat, "Archive", archivePendingIntent)
|
||||||
|
cnb.addAction(R.drawable.ic_stat, "Delete", deletePendingIntent)
|
||||||
|
nm.notify(MESSAGE_NOTIFICATION_ID, cnb.build())
|
||||||
|
}
|
||||||
|
val intent = Intent("service event")
|
||||||
|
intent.putExtra("event", "message")
|
||||||
|
intent.putExtra("params", arrayListOf(uap, peer, s, timeStamp))
|
||||||
|
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateStatusNotification() {
|
private fun updateStatusNotification() {
|
||||||
val contentView = RemoteViews(getPackageName(), R.layout.status_notification)
|
val contentView = RemoteViews(getPackageName(), R.layout.status_notification)
|
||||||
for (i: Int in 0 .. 5) {
|
for (i: Int in 0 .. 5) {
|
||||||
@ -321,9 +404,11 @@ class BaresipService: Service() {
|
|||||||
|
|
||||||
private fun cleanStop() {
|
private fun cleanStop() {
|
||||||
HistoryActivity.saveHistory()
|
HistoryActivity.saveHistory()
|
||||||
|
MessagesActivity.saveMessages()
|
||||||
MainActivity.uas.clear()
|
MainActivity.uas.clear()
|
||||||
MainActivity.images.clear()
|
MainActivity.images.clear()
|
||||||
MainActivity.history.clear()
|
MainActivity.history.clear()
|
||||||
|
MainActivity.messages.clear()
|
||||||
baresipStop()
|
baresipStop()
|
||||||
BaresipService.IS_SERVICE_RUNNING = false
|
BaresipService.IS_SERVICE_RUNNING = false
|
||||||
unregisterReceiver(nr)
|
unregisterReceiver(nr)
|
||||||
@ -339,8 +424,9 @@ class BaresipService: Service() {
|
|||||||
|
|
||||||
var IS_SERVICE_RUNNING = false
|
var IS_SERVICE_RUNNING = false
|
||||||
val STATUS_NOTIFICATION_ID = 101
|
val STATUS_NOTIFICATION_ID = 101
|
||||||
val DEFAULT_CHANNEL_ID = "com.tutpro.baresip.default"
|
|
||||||
val CALL_NOTIFICATION_ID = 102
|
val CALL_NOTIFICATION_ID = 102
|
||||||
|
val MESSAGE_NOTIFICATION_ID = 103
|
||||||
|
val DEFAULT_CHANNEL_ID = "com.tutpro.baresip.default"
|
||||||
val HIGH_CHANNEL_ID = "com.tutpro.baresip.high"
|
val HIGH_CHANNEL_ID = "com.tutpro.baresip.high"
|
||||||
var disconnected = false
|
var disconnected = false
|
||||||
val RUN_FOREGROUNG = false
|
val RUN_FOREGROUNG = false
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import android.widget.RelativeLayout
|
|||||||
import android.widget.*
|
import android.widget.*
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@ -39,7 +40,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
internal lateinit var securityButton: ImageButton
|
internal lateinit var securityButton: ImageButton
|
||||||
internal lateinit var callButton: ImageButton
|
internal lateinit var callButton: ImageButton
|
||||||
internal lateinit var holdButton: ImageButton
|
internal lateinit var holdButton: ImageButton
|
||||||
internal lateinit var historyButton: ImageButton
|
internal lateinit var messagesButton: ImageButton
|
||||||
|
internal lateinit var callsButton: ImageButton
|
||||||
internal lateinit var dtmf: EditText
|
internal lateinit var dtmf: EditText
|
||||||
internal lateinit var uaAdapter: UaSpinnerAdapter
|
internal lateinit var uaAdapter: UaSpinnerAdapter
|
||||||
internal lateinit var aorSpinner: Spinner
|
internal lateinit var aorSpinner: Spinner
|
||||||
@ -70,7 +72,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
securityButton = findViewById(R.id.securityButton) as ImageButton
|
securityButton = findViewById(R.id.securityButton) as ImageButton
|
||||||
callButton = findViewById(R.id.callButton) as ImageButton
|
callButton = findViewById(R.id.callButton) as ImageButton
|
||||||
holdButton = findViewById(R.id.holdButton) as ImageButton
|
holdButton = findViewById(R.id.holdButton) as ImageButton
|
||||||
historyButton = findViewById(R.id.historyButton) as ImageButton
|
messagesButton = findViewById(R.id.messagesButton) as ImageButton
|
||||||
|
callsButton = findViewById(R.id.callsButton) as ImageButton
|
||||||
dtmf = findViewById(R.id.dtmf) as EditText
|
dtmf = findViewById(R.id.dtmf) as EditText
|
||||||
|
|
||||||
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
@ -83,8 +86,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
serviceEventReceiver = object : BroadcastReceiver() {
|
serviceEventReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
handleServiceEvent(intent.getStringExtra("event"),
|
handleServiceEvent(intent.getStringExtra("event"),
|
||||||
intent.getStringExtra("uap"),
|
intent.getStringArrayListExtra("params"))
|
||||||
intent.getStringExtra("callp"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(serviceEventReceiver,
|
LocalBroadcastManager.getInstance(this).registerReceiver(serviceEventReceiver,
|
||||||
@ -114,11 +116,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
callee.hint = "Callee"
|
callee.hint = "Callee"
|
||||||
callButton.tag = "Call"
|
callButton.tag = "Call"
|
||||||
callButton.setImageResource(R.drawable.call)
|
callButton.setImageResource(R.drawable.call)
|
||||||
if (History.aorHistory(history, aor) > 0) {
|
|
||||||
historyButton.visibility = View.VISIBLE
|
|
||||||
} else {
|
|
||||||
historyButton.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
securityButton.visibility = View.INVISIBLE
|
securityButton.visibility = View.INVISIBLE
|
||||||
dtmf.visibility = View.INVISIBLE
|
dtmf.visibility = View.INVISIBLE
|
||||||
} else {
|
} else {
|
||||||
@ -147,8 +144,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
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 > 8)
|
||||||
layout.removeViews(7, view_count - 7)
|
layout.removeViews(8, view_count - 8)
|
||||||
for (c in Call.uaCalls(calls, ua, "in"))
|
for (c in Call.uaCalls(calls, ua, "in"))
|
||||||
for (call_index in Call.uaCalls(calls, ua, "in").indices) {
|
for (call_index in Call.uaCalls(calls, ua, "in").indices) {
|
||||||
val startIndex = (call_index + 1) * 10
|
val startIndex = (call_index + 1) * 10
|
||||||
@ -294,8 +291,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
historyButton.visibility = View.INVISIBLE
|
messagesButton.setOnClickListener {
|
||||||
historyButton.setOnClickListener {
|
val i = Intent(this@MainActivity, MessagesActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("aor", uas[aorSpinner.selectedItemPosition].account.aor)
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivityForResult(i, MESSAGES_CODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
callsButton.visibility = View.VISIBLE
|
||||||
|
callsButton.setOnClickListener {
|
||||||
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", uas[aorSpinner.selectedItemPosition].account.aor)
|
b.putString("aor", uas[aorSpinner.selectedItemPosition].account.aor)
|
||||||
@ -313,16 +318,17 @@ class MainActivity : AppCompatActivity() {
|
|||||||
moveTaskToBack(true)
|
moveTaskToBack(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleServiceEvent(event: String, uap: String, callp: String) {
|
private fun handleServiceEvent(event: String, params: ArrayList<String>) {
|
||||||
|
val uap = params[0]
|
||||||
val ua = UserAgent.find(uas, uap)
|
val ua = UserAgent.find(uas, uap)
|
||||||
if (ua == null) {
|
if (ua == null) {
|
||||||
Log.w("Baresip", "handleServiceEvent '$event' did not find ua $uap")
|
Log.w("Baresip", "handleServiceEvent '$event' did not find ua $uap")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val ev = event.split(",")
|
||||||
|
Log.d("Baresip", "Handling service event ${ev[0]} for $uap")
|
||||||
val aor = ua.account.aor
|
val aor = ua.account.aor
|
||||||
val acc = ua.account
|
val acc = ua.account
|
||||||
val ev = event.split(",")
|
|
||||||
Log.d("Baresip", "Handling service event ${ev[0]} for $uap/$callp/$aor")
|
|
||||||
for (account_index in uas.indices) {
|
for (account_index in uas.indices) {
|
||||||
if (uas[account_index].account.aor == aor) {
|
if (uas[account_index].account.aor == aor) {
|
||||||
when (ev[0]) {
|
when (ev[0]) {
|
||||||
@ -334,6 +340,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
uaAdapter.notifyDataSetChanged()
|
uaAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
"call incoming" -> {
|
"call incoming" -> {
|
||||||
|
val callp = params[1]
|
||||||
val peer_uri = Api.call_peeruri(callp)
|
val peer_uri = Api.call_peeruri(callp)
|
||||||
val new_call = Call(callp, ua, peer_uri, "in", "Answer", null)
|
val new_call = Call(callp, ua, peer_uri, "in", "Answer", null)
|
||||||
if (ONE_CALL_ONLY && (calls.size > 0)) {
|
if (ONE_CALL_ONLY && (calls.size > 0)) {
|
||||||
@ -359,6 +366,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"call established" -> {
|
"call established" -> {
|
||||||
|
val callp = params[1]
|
||||||
val call = Call.find(calls, callp)
|
val call = Call.find(calls, callp)
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
Log.e("Baresip", "Established call $callp not found")
|
Log.e("Baresip", "Established call $callp not found")
|
||||||
@ -424,6 +432,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
History.aorRemoveHistory(history, aor)
|
History.aorRemoveHistory(history, aor)
|
||||||
}
|
}
|
||||||
"call verify" -> {
|
"call verify" -> {
|
||||||
|
val callp = params[1]
|
||||||
val call = Call.find(calls, callp)
|
val call = Call.find(calls, callp)
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
Log.e("Baresip", "Call $callp to be verified is not found")
|
Log.e("Baresip", "Call $callp to be verified is not found")
|
||||||
@ -478,6 +487,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
verifyDialog.create().show()
|
verifyDialog.create().show()
|
||||||
}
|
}
|
||||||
"call verified", "call secure" -> {
|
"call verified", "call secure" -> {
|
||||||
|
val callp = params[1]
|
||||||
val call = Call.find(calls, callp)
|
val call = Call.find(calls, callp)
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
Log.e("Baresip", "Call $callp that is verified is not found")
|
Log.e("Baresip", "Call $callp that is verified is not found")
|
||||||
@ -509,6 +519,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"call closed" -> {
|
"call closed" -> {
|
||||||
|
val callp = params[1]
|
||||||
val call = Call.find(calls, callp)
|
val call = Call.find(calls, callp)
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
Log.d("Baresip", "Call $callp that is closed is not found")
|
Log.d("Baresip", "Call $callp that is closed is not found")
|
||||||
@ -534,7 +545,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
addCallViews(ua, callsIn[i], (i + 1) * 10)
|
addCallViews(ua, callsIn[i], (i + 1) * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyButton.visibility = View.VISIBLE
|
callsButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
if (!call.hasHistory) {
|
if (!call.hasHistory) {
|
||||||
if (History.aorHistory(history, aor) > HISTORY_SIZE)
|
if (History.aorHistory(history, aor) > HISTORY_SIZE)
|
||||||
@ -558,7 +569,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
securityButton.visibility = View.INVISIBLE
|
securityButton.visibility = View.INVISIBLE
|
||||||
dtmf.removeTextChangedListener(call.dtmfWatcher)
|
dtmf.removeTextChangedListener(call.dtmfWatcher)
|
||||||
dtmf.visibility = View.INVISIBLE
|
dtmf.visibility = View.INVISIBLE
|
||||||
historyButton.visibility = View.VISIBLE
|
messagesButton.visibility = View.VISIBLE
|
||||||
|
callsButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
calls.remove(call)
|
calls.remove(call)
|
||||||
if (!call.hasHistory) {
|
if (!call.hasHistory) {
|
||||||
@ -570,6 +582,25 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
if (calls.size == 0) am.mode = AudioManager.MODE_NORMAL
|
if (calls.size == 0) am.mode = AudioManager.MODE_NORMAL
|
||||||
}
|
}
|
||||||
|
"message" -> {
|
||||||
|
val peer_uri = params[1]
|
||||||
|
val msg = params[2]
|
||||||
|
val time = params[3]
|
||||||
|
val new_message = Message(aor, peer_uri, R.drawable.arrow_down_green, msg,
|
||||||
|
time.toLong(), true)
|
||||||
|
Log.d("Baresip", "Incoming message $aor/$peer_uri/$msg")
|
||||||
|
messages.add(new_message)
|
||||||
|
if (Utils.isVisible()) {
|
||||||
|
if (ua != uas[aorSpinner.selectedItemPosition])
|
||||||
|
aorSpinner.setSelection(account_index)
|
||||||
|
val i = Intent(applicationContext, MessagesActivity::class.java)
|
||||||
|
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("aor", ua.account.aor)
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivity(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> Log.w("Baresip", "Unknown event '${ev[0]}'")
|
else -> Log.w("Baresip", "Unknown event '${ev[0]}'")
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -581,16 +612,52 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setIntent(intent)
|
setIntent(intent)
|
||||||
val action = intent.getStringExtra("action")
|
val action = intent.getStringExtra("action")
|
||||||
Log.d("Baresip", "Got onNewIntent action $action")
|
Log.d("Baresip", "Got onNewIntent action $action")
|
||||||
if (action == null) return
|
|
||||||
val callp = intent.getStringExtra("callp")
|
|
||||||
when (action) {
|
when (action) {
|
||||||
"answer" -> {
|
"answer" -> {
|
||||||
answerCall = callp
|
answerCall = intent.getStringExtra("callp")
|
||||||
}
|
}
|
||||||
"reject" -> {
|
"reject" -> {
|
||||||
rejectCall = callp
|
rejectCall = intent.getStringExtra("callp")
|
||||||
moveTaskToBack(true)
|
moveTaskToBack(true)
|
||||||
}
|
}
|
||||||
|
"reply", "archive", "delete" -> {
|
||||||
|
val uap = intent.getStringExtra("uap")
|
||||||
|
val ua = UserAgent.find(MainActivity.uas, uap)
|
||||||
|
if (ua == null) {
|
||||||
|
Log.e("Baresip", "onNewIntent did not find ua $uap")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val aor = ua.account.aor
|
||||||
|
when (action) {
|
||||||
|
"reply" -> {
|
||||||
|
val i = Intent(this@MainActivity, MessagesActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
if (ua != uas[aorSpinner.selectedItemPosition]) {
|
||||||
|
for (account_index in uas.indices) {
|
||||||
|
if (uas[account_index].account.aor == aor) {
|
||||||
|
aorSpinner.setSelection(account_index)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.putString("aor", aor)
|
||||||
|
b.putString("peer", intent.getStringExtra("peer"))
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivityForResult(i, MESSAGES_CODE)
|
||||||
|
}
|
||||||
|
"archive" -> {
|
||||||
|
MessagesActivity.archiveUaMessage(ua.account.aor,
|
||||||
|
intent.getStringExtra("time").toLong())
|
||||||
|
moveTaskToBack(true)
|
||||||
|
}
|
||||||
|
"delete" -> {
|
||||||
|
MessagesActivity.deleteUaMessage(ua.account.aor,
|
||||||
|
intent.getStringExtra("time").toLong())
|
||||||
|
moveTaskToBack(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nm.cancel(BaresipService.MESSAGE_NOTIFICATION_ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,13 +672,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
Log.d("Baresip", "Resumed")
|
Log.d("Baresip", "Resumed")
|
||||||
imm.hideSoftInputFromWindow(callee.windowToken, 0)
|
imm.hideSoftInputFromWindow(callee.windowToken, 0)
|
||||||
visible = true
|
visible = true
|
||||||
if ((answerCall != "") && (layout.childCount > 7)) {
|
if ((answerCall != "") && (layout.childCount > 8)) {
|
||||||
answerCall = ""
|
answerCall = ""
|
||||||
/* if multiple calls, right answer button needs to be searched */
|
/* if multiple calls, right answer button needs to be searched */
|
||||||
val answerButton = layout.findViewById(10 + 5) as ImageButton
|
val answerButton = layout.findViewById(10 + 5) as ImageButton
|
||||||
answerButton.performClick()
|
answerButton.performClick()
|
||||||
}
|
}
|
||||||
if ((rejectCall != "") && (layout.childCount > 7)) {
|
if ((rejectCall != "") && (layout.childCount > 8)) {
|
||||||
rejectCall = ""
|
rejectCall = ""
|
||||||
/* if multiple calls, right reject button needs to be searched */
|
/* if multiple calls, right reject button needs to be searched */
|
||||||
val rejectButton = layout.findViewById(10 + 6) as ImageButton
|
val rejectButton = layout.findViewById(10 + 6) as ImageButton
|
||||||
@ -996,6 +1063,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
internal var images = ArrayList<Int>()
|
internal var images = ArrayList<Int>()
|
||||||
var history: ArrayList<History> = ArrayList()
|
var history: ArrayList<History> = ArrayList()
|
||||||
internal var calls = ArrayList<Call>()
|
internal var calls = ArrayList<Call>()
|
||||||
|
internal var messages = ArrayList<Message>()
|
||||||
var filesPath = ""
|
var filesPath = ""
|
||||||
var visible = true
|
var visible = true
|
||||||
var answerCall = ""
|
var answerCall = ""
|
||||||
@ -1008,9 +1076,12 @@ class MainActivity : AppCompatActivity() {
|
|||||||
const val ABOUT_CODE = 5
|
const val ABOUT_CODE = 5
|
||||||
const val ACCOUNT_CODE = 6
|
const val ACCOUNT_CODE = 6
|
||||||
const val CONTACT_CODE = 7
|
const val CONTACT_CODE = 7
|
||||||
|
const val MESSAGES_CODE = 8
|
||||||
|
const val MESSAGE_CODE = 9
|
||||||
|
|
||||||
const val RECORD_AUDIO_PERMISSION = 1
|
const val RECORD_AUDIO_PERMISSION = 1
|
||||||
const val HISTORY_SIZE = 100
|
const val HISTORY_SIZE = 100
|
||||||
|
const val MESSAGE_HISTORY_SIZE = 100
|
||||||
const val ONE_CALL_ONLY = true
|
const val ONE_CALL_ONLY = true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
7
app/src/main/kotlin/com/tutpro/baresip/Message.kt
Normal file
7
app/src/main/kotlin/com/tutpro/baresip/Message.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
class Message(val aor: String, val peerURI: String, val direction: Int, val message: String,
|
||||||
|
val timeStamp: Long, var new: Boolean): Serializable {
|
||||||
|
}
|
||||||
102
app/src/main/kotlin/com/tutpro/baresip/MessageActivity.kt
Normal file
102
app/src/main/kotlin/com/tutpro/baresip/MessageActivity.kt
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.*
|
||||||
|
|
||||||
|
class MessageActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
internal lateinit var receiver: AutoCompleteTextView
|
||||||
|
internal lateinit var message: EditText
|
||||||
|
internal lateinit var sendButton: ImageButton
|
||||||
|
internal lateinit var imm: InputMethodManager
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_message)
|
||||||
|
|
||||||
|
val aor = intent.extras.getString("aor")
|
||||||
|
val peerURI = intent.extras.getString("peer")
|
||||||
|
|
||||||
|
val ua = Account.findUa(aor)
|
||||||
|
if (ua == null) {
|
||||||
|
Log.e("Baresip", "MessageActivity did not find ua of $aor")
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
val title = findViewById(R.id.messageToTitle) as TextView
|
||||||
|
message = findViewById(R.id.text) as EditText
|
||||||
|
receiver = findViewById(R.id.receiver) as AutoCompleteTextView
|
||||||
|
|
||||||
|
imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
|
||||||
|
if (peerURI == "") {
|
||||||
|
title.text = "Message to ..."
|
||||||
|
receiver.threshold = 2
|
||||||
|
receiver.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
|
||||||
|
ContactsActivity.contacts.map { Contact -> Contact.name }))
|
||||||
|
receiver.requestFocus()
|
||||||
|
} else {
|
||||||
|
title.text = "Reply to ..."
|
||||||
|
receiver.setText(ContactsActivity.contactName(peerURI), false)
|
||||||
|
message.requestFocus()
|
||||||
|
}
|
||||||
|
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)
|
||||||
|
|
||||||
|
sendButton = findViewById(R.id.sendButton) as ImageButton
|
||||||
|
sendButton.setOnClickListener {
|
||||||
|
val receiverText = receiver.text.toString()
|
||||||
|
val msg = message.text.toString()
|
||||||
|
if (receiverText.length > 0) {
|
||||||
|
var uri = ContactsActivity.findContactURI(receiverText)
|
||||||
|
if (!uri.startsWith("sip:")) uri = "sip:$uri"
|
||||||
|
if (!uri.contains("@")) {
|
||||||
|
val host = aor.substring(aor.indexOf("@") + 1)
|
||||||
|
uri = "$uri@$host"
|
||||||
|
}
|
||||||
|
if (msg.length > 0) {
|
||||||
|
imm.hideSoftInputFromWindow(receiver.getWindowToken(), 0)
|
||||||
|
imm.hideSoftInputFromWindow(message.getWindowToken(), 0)
|
||||||
|
val res = message_send(ua!!.uap, uri, msg)
|
||||||
|
if (res != 0) {
|
||||||
|
Toast.makeText(getApplicationContext(), "Sending of message failed!",
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
} else {
|
||||||
|
val new_message = Message(aor, uri, R.drawable.arrow_up_green, msg,
|
||||||
|
System.currentTimeMillis(), false)
|
||||||
|
MainActivity.messages.add(new_message)
|
||||||
|
MessagesActivity.uaMessages.add(0, new_message)
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_OK, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
android.R.id.home -> {
|
||||||
|
imm.hideSoftInputFromWindow(receiver.getWindowToken(), 0)
|
||||||
|
imm.hideSoftInputFromWindow(message.getWindowToken(), 0)
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
external fun message_send(uap: String, peer_uri: String, message: String) : Int
|
||||||
|
|
||||||
|
}
|
||||||
47
app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt
Normal file
47
app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.text.format.DateUtils.isToday
|
||||||
|
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.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MessageListAdapter(private val cxt: Context, private val rows: ArrayList<Message>) :
|
||||||
|
ArrayAdapter<Message>(cxt, R.layout.message, rows) {
|
||||||
|
|
||||||
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
val message = rows[position]
|
||||||
|
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
val messageView = inflater.inflate(R.layout.message, parent, false)
|
||||||
|
val directionView = messageView.findViewById(R.id.direction) as ImageView
|
||||||
|
directionView.setImageResource(message.direction)
|
||||||
|
val peerView = messageView.findViewById(R.id.peer) as TextView
|
||||||
|
peerView.text = ContactsActivity.contactName(message.peerURI)
|
||||||
|
val timeView = messageView.findViewById(R.id.time) as TextView
|
||||||
|
val time: String
|
||||||
|
val cal = GregorianCalendar()
|
||||||
|
cal.timeInMillis = message.timeStamp
|
||||||
|
if (isToday(message.timeStamp)) {
|
||||||
|
val fmt = SimpleDateFormat("HH:mm")
|
||||||
|
time = fmt.format(cal.time)
|
||||||
|
} else {
|
||||||
|
val fmt = SimpleDateFormat("dd.MM")
|
||||||
|
time = fmt.format(cal.time)
|
||||||
|
}
|
||||||
|
timeView.text = time
|
||||||
|
val textView = messageView.findViewById(R.id.text) as TextView
|
||||||
|
textView.text = message.message
|
||||||
|
if (message.new) {
|
||||||
|
textView.setTypeface(null, Typeface.BOLD)
|
||||||
|
message.new = false
|
||||||
|
}
|
||||||
|
return messageView
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
166
app/src/main/kotlin/com/tutpro/baresip/MessagesActivity.kt
Normal file
166
app/src/main/kotlin/com/tutpro/baresip/MessagesActivity.kt
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AlertDialog
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.widget.AdapterView
|
||||||
|
import android.widget.ImageButton
|
||||||
|
import android.widget.ListView
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MessagesActivity: AppCompatActivity() {
|
||||||
|
|
||||||
|
internal lateinit var aor: String
|
||||||
|
internal lateinit var mlAdapter: MessageListAdapter
|
||||||
|
internal lateinit var plusButton: ImageButton
|
||||||
|
|
||||||
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_messages)
|
||||||
|
|
||||||
|
val listView = findViewById(R.id.message) as ListView
|
||||||
|
plusButton = findViewById(R.id.plusButton) as ImageButton
|
||||||
|
|
||||||
|
aor = intent.extras.getString("aor")
|
||||||
|
uaMessages = uaMessages(aor)
|
||||||
|
|
||||||
|
mlAdapter = MessageListAdapter(this, uaMessages)
|
||||||
|
listView.adapter = mlAdapter
|
||||||
|
listView.isLongClickable = true
|
||||||
|
|
||||||
|
listView.onItemClickListener = AdapterView.OnItemClickListener { _, _, pos, _ ->
|
||||||
|
val i = Intent(this@MessagesActivity, MessageActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("aor", aor)
|
||||||
|
b.putString("peer", uaMessages[pos].peerURI)
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivityForResult(i, MainActivity.MESSAGE_CODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
listView.onItemLongClickListener = AdapterView.OnItemLongClickListener { _, _, pos, _ ->
|
||||||
|
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||||
|
when (which) {
|
||||||
|
DialogInterface.BUTTON_NEGATIVE -> {
|
||||||
|
MainActivity.messages.remove(uaMessages[pos])
|
||||||
|
uaMessages.removeAt(pos)
|
||||||
|
if (uaMessages.size == 0) {
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
mlAdapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
DialogInterface.BUTTON_POSITIVE -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val builder = AlertDialog.Builder(this@MessagesActivity,
|
||||||
|
R.style.Theme_AppCompat)
|
||||||
|
builder.setMessage("Delete message from " +
|
||||||
|
ContactsActivity.contactName(uaMessages[pos].peerURI) + "?")
|
||||||
|
.setPositiveButton("Cancel", dialogClickListener)
|
||||||
|
.setNegativeButton("Delete", dialogClickListener)
|
||||||
|
.show()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
plusButton.setOnClickListener {
|
||||||
|
val i = Intent(this@MessagesActivity, MessageActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("aor", aor)
|
||||||
|
b.putString("peer", "")
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivityForResult(i, MainActivity.MESSAGE_CODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
val peer = intent.extras.getString("peer")
|
||||||
|
if (peer != null) {
|
||||||
|
val i = Intent(this@MessagesActivity, MessageActivity::class.java)
|
||||||
|
val b = Bundle()
|
||||||
|
b.putString("aor", aor)
|
||||||
|
b.putString("peer", peer)
|
||||||
|
i.putExtras(b)
|
||||||
|
startActivityForResult(i, MainActivity.MESSAGE_CODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
android.R.id.home -> {
|
||||||
|
Log.d("Baresip", "Back array was pressed at Messages")
|
||||||
|
val i = Intent()
|
||||||
|
setResult(Activity.RESULT_CANCELED, i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
when (requestCode) {
|
||||||
|
MainActivity.MESSAGE_CODE -> {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
mlAdapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun uaMessages(aor: String) : ArrayList<Message> {
|
||||||
|
val res = ArrayList<Message>()
|
||||||
|
for (m in MainActivity.messages.reversed()) {
|
||||||
|
if (m.aor == aor) {
|
||||||
|
res.add(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
var uaMessages = ArrayList<Message>()
|
||||||
|
|
||||||
|
fun archiveUaMessage(aor: String, time: Long) {
|
||||||
|
for (i in MainActivity.messages.indices.reversed())
|
||||||
|
if ((MainActivity.messages[i].aor == aor) &&
|
||||||
|
(MainActivity.messages[i].timeStamp == time)) {
|
||||||
|
MainActivity.messages[i].new = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteUaMessage(aor: String, time: Long) {
|
||||||
|
for (i in MainActivity.messages.indices.reversed())
|
||||||
|
if ((MainActivity.messages[i].aor == aor) &&
|
||||||
|
(MainActivity.messages[i].timeStamp == time)) {
|
||||||
|
MainActivity.messages.removeAt(i)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveMessages() {
|
||||||
|
val file = File(MainActivity.filesPath, "messages")
|
||||||
|
try {
|
||||||
|
val fos = FileOutputStream(file)
|
||||||
|
val oos = ObjectOutputStream(fos)
|
||||||
|
oos.writeObject(MainActivity.messages)
|
||||||
|
oos.close()
|
||||||
|
fos.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.w("Baresip", "OutputStream exception: " + e.toString())
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@ class RunOnStartup : BroadcastReceiver() {
|
|||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
if ((intent.action == Intent.ACTION_BOOT_COMPLETED) or
|
if ((intent.action == Intent.ACTION_BOOT_COMPLETED) or
|
||||||
(intent.action == "com.tutpro.baresip.Restart")) {
|
(intent.action == "com.tutpro.baresip.Restart")) {
|
||||||
Log.d("Baresip", "Start baresip upon boot completed or restart")
|
Log.d("Baresip", "Start baresip upon boot completed or restart")
|
||||||
val i = Intent(context, MainActivity::class.java)
|
val i = Intent(context, MainActivity::class.java)
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
val b = Bundle()
|
val b = Bundle()
|
||||||
|
|||||||
5
app/src/main/res/drawable/calls.xml
Normal file
5
app/src/main/res/drawable/calls.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="48dp" android:tint="#00ACC1"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
|
||||||
|
</vector>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
5
app/src/main/res/drawable/messages.xml
Normal file
5
app/src/main/res/drawable/messages.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="44dp" android:tint="#00ACC1"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="44dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM6,9h12v2L6,11L6,9zM14,14L6,14v-2h8v2zM18,8L6,8L6,6h12v2z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/plus.xml
Normal file
5
app/src/main/res/drawable/plus.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="48dp" android:tint="#00ACC1"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/send.xml
Normal file
5
app/src/main/res/drawable/send.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="36dp" android:tint="#00ACC1"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="36dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
|
||||||
|
</vector>
|
||||||
@ -100,16 +100,30 @@
|
|||||||
</EditText>
|
</EditText>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/historyButton"
|
android:id="@+id/messagesButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/calleeRow"
|
||||||
|
android:layout_toStartOf="@id/callsButton"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:background="@null"
|
||||||
|
android:src="@drawable/messages"
|
||||||
|
android:visibility="visible" >
|
||||||
|
</ImageButton>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/callsButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/calleeRow"
|
android:layout_below="@id/calleeRow"
|
||||||
android:padding="0dp"
|
android:padding="0dp"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
android:src="@drawable/clock"
|
android:src="@drawable/calls"
|
||||||
android:layout_marginEnd="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:visibility="invisible" >
|
android:visibility="visible" >
|
||||||
</ImageButton>
|
</ImageButton>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|||||||
50
app/src/main/res/layout/activity_message.xml
Normal file
50
app/src/main/res/layout/activity_message.xml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?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:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:context="com.tutpro.baresip.MessageActivity" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messageToTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:text="Message to ..." >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<AutoCompleteTextView
|
||||||
|
android:id="@+id/receiver"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textEmailAddress"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:hint="Contact name or SIP URI" >
|
||||||
|
<requestFocus />
|
||||||
|
</AutoCompleteTextView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:scrollHorizontally="false"
|
||||||
|
android:hint="Message">
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/sendButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:src="@drawable/send"
|
||||||
|
android:background="@null" >
|
||||||
|
</ImageButton>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
29
app/src/main/res/layout/activity_messages.xml
Normal file
29
app/src/main/res/layout/activity_messages.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout 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: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.MessagesActivity">
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/message"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/plusButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/plus"
|
||||||
|
android:background="@null"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentBottom="true" >
|
||||||
|
</ImageButton>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
51
app/src/main/res/layout/message.xml
Normal file
51
app/src/main/res/layout/message.xml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="0dp"
|
||||||
|
android:layout_marginTop="0dp" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/header"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp" >
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/direction"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/peer"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/time"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="" >
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -36,4 +36,5 @@
|
|||||||
EMPTY value means that media encryption is not supported and that media transport protocol
|
EMPTY value means that media encryption is not supported and that media transport protocol
|
||||||
thus is RTP/AVP.
|
thus is RTP/AVP.
|
||||||
</string>
|
</string>
|
||||||
|
<string name="title_activity_message">MessageActivity</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user