- added EditContactsActivity

- if needed, ask permission to use microphone
- small layout improvements
- targetSdkVersion is not 25
This commit is contained in:
Juha Heinanen
2018-02-25 21:01:46 +02:00
parent babe009f2e
commit 4d8431a643
16 changed files with 255 additions and 115 deletions

View File

@ -6,7 +6,7 @@ android {
defaultConfig {
applicationId = 'com.tutpro.baresip'
minSdkVersion 21
targetSdkVersion 23
targetSdkVersion 25
versionCode = 1
versionName = '1.0'
ndk {

View File

@ -36,7 +36,7 @@
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@ -52,16 +52,6 @@
</intent-filter>
</activity>
<activity
android:name=".AccountsActivity"
android:label="Accounts"
android:parentActivityName=".MainActivity"
android:theme="@style/AppTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.tutpro.baresip.MainActivity" />
</activity>
<activity
android:name=".EditAccountsActivity"
android:label="Edit Accounts"
@ -82,7 +72,7 @@
android:value="com.tutpro.baresip.MainActivity" />
</activity>
<!-- <activity
<activity
android:name=".EditContactsActivity"
android:label="Edit Contacts"
android:parentActivityName=".MainActivity"
@ -90,7 +80,7 @@
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.tutpro.baresip.MainActivity" />
</activity> -->
</activity>
<activity
android:name=".AboutActivity"

View File

@ -31,4 +31,4 @@
# <sip:user@1.2.3.4;auth_pass=secret;transport=tcp>
# <sip:user@[2001:df8:0:16:216:6fff:fe91:614c]:5070;transport=tcp;auth_pass=secret>
#
<sip:foo@test.tutpro.com>;auth_user=foo;auth_pass=xxx;outbound="sip:192.168.43.98:5060;transport=tcp";ptime=20;audio_codecs=OPUS/48000/2,speex/16000,speex/8000;video_codecs="";regint=600;pubint=0;sipnat=outbound
<sip:foo@test.tutpro.com>;auth_user=foo;auth_pass=xxx;outbound="sip:192.168.43.98:5060;transport=tcp";ptime=20;audio_codecs=OPUS/48000/2,speex/16000,speex/8000,PCMU,PCMA;video_codecs="";regint=600;pubint=0;sipnat=outbound

View File

@ -19,27 +19,27 @@ call_max_calls 4
# Audio
audio_player opensles,nil
audio_source opensles,nil
audio_alert opensles,nil
audio_srate 8000-48000
audio_alert opensles,nil
audio_srate 8000-48000
audio_channels 1-2
#ausrc_srate 48000
#auplay_srate 48000
#ausrc_channels 0
#auplay_channels 0
audio_level no
audio_level no
# Video
#video_source v4l2,/dev/video0
#video_display x11,nil
video_size 352x288
video_size 352x288
video_bitrate 500000
video_fps 25
video_fps 25
video_fullscreen yes
# AVT - Audio/Video Transport
rtp_tos 184
#rtp_ports 10000-20000
#rtp_bandwidth 512-1024 # [kbit/s]
#rtp_bandwidth 512-1024 # [kbit/s]
rtcp_enable yes
rtcp_mux no
jitter_buffer_delay 5-10 # frames
@ -176,13 +176,13 @@ speex_complexity 7 # 0-10
speex_enhancement 0 # 0-1
speex_mode_nb 3 # 1-6
speex_mode_wb 6 # 1-6
speex_vbr 0 # Variable Bit Rate 0-1
speex_vad 0 # Voice Activity Detection 0-1
speex_vbr 0 # Variable Bit Rate 0-1
speex_vad 0 # Voice Activity Detection 0-1
speex_agc_level 8000
# Opus codec parameters
opus_bitrate 28000 # 6000-510000
opus_cbr no
opus_cbr no
opus_inbandfec yes
# Selfview
@ -192,7 +192,7 @@ opus_inbandfec yes
# ICE
ice_turn no
ice_debug no
ice_nomination regular # {regular,aggressive}
ice_nomination regular # {regular,aggressive}
ice_mode full # {full,lite}
# Menu

View File

@ -1,17 +1,20 @@
#
# SIP contacts
#
# Displayname <sip:user@domain>;addr-params
# "display-name" <sip:user@domain>;addr-params
#
# display-name:
# needs to be at least two characters long
#
# addr-params:
# ;presence={none,p2p}
# ;access={allow,block}
#
# Peer contacts
"Echo Server" <sip:echo@creytiv.com>
#"user" <sip:user@domain>;presence=p2p
# Access rules
#"Catch All" <sip:*@*>;access=block
#"Good Friend" <sip:good@friend.com>;access=allow

View File

@ -456,3 +456,31 @@ Java_com_tutpro_baresip_MainActivity_ua_1hangup(JNIEnv *env, jobject thiz,
(*env)->ReleaseStringUTFChars(env, reason, native_reason);
return;
}
JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_contacts_1remove(JNIEnv *env, jobject thiz) {
struct le *le;
le = list_head(contact_list(baresip_contacts()));
while ((le = list_head(contact_list(baresip_contacts())))) {
struct contact *c = le->data;
contact_remove(baresip_contacts(), c);
}
return;
}
JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_contact_1add(JNIEnv *env, jobject thiz,
jstring javaContact) {
struct pl pl_addr;
const struct list *lst;
struct le *le;
const char *native_contact = (*env)->GetStringUTFChars(env, javaContact, 0);
pl_set_str(&pl_addr, native_contact);
if (contact_add(baresip_contacts(), NULL, &pl_addr) != 0) {
LOGE("failed to add contact %s\n", native_contact);
} else {
LOGD("added contact %s\n", native_contact);
}
return;
}

View File

@ -38,6 +38,7 @@ public class AccountSpinnerAdapter extends ArrayAdapter<Integer> {
View row = inflater.inflate(R.layout.account_spinner, parent, false);
TextView textView = (TextView) row.findViewById(R.id.spinnerText);
textView.setText(aors.get(position));
textView.setTextSize(17);
ImageView imageView = (ImageView) row.findViewById(R.id.spinnerImage);
imageView.setImageResource(images.get(position));
return row;

View File

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

View File

@ -8,53 +8,28 @@ import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.TextView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
public class EditContactsActivity extends AppCompatActivity {
private EditText editText;
private String path;
private File file;
static public ArrayList<Contact> Contacts = new java.util.ArrayList<>();
static public ArrayList<String> Names = new java.util.ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_contacts);
editText = (EditText)findViewById(R.id.editText);
path = getApplicationContext().getFilesDir().getAbsolutePath() +
"/contacts";
file = new File(path);
String content;
if (!file.exists()) {
Log.e("Baresip", "Failed to find contacts file");
content = "No contacts";
} else {
Log.e("Baresip", "Found contacts file");
int length = (int)file.length();
byte[] bytes = new byte[length];
try {
FileInputStream in = new FileInputStream(file);
try {
in.read(bytes);
} finally {
in.close();
}
content = new String(bytes);
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to read contacts file: " + e.toString());
content = "Failed to read account file";
}
}
Log.d("Baresip", "Content length is: " + content.length());
String path = getApplicationContext().getFilesDir().getAbsolutePath() + "/contacts";
File file = new File(path);
String content = Utils.getFileContents(file);
Log.d("Baresip", "Contacts length is: " + content.length());
editText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.textsize));
editText.setText(content, TextView.BufferType.EDITABLE);
@ -71,34 +46,71 @@ public class EditContactsActivity extends AppCompatActivity {
Intent i = new Intent(this, MainActivity.class);
switch (item.getItemId()) {
case R.id.save:
try {
FileOutputStream fOut =
new FileOutputStream(file.getAbsoluteFile(), false);
OutputStreamWriter fWriter = new OutputStreamWriter(fOut);
String res = editText.getText().toString();
try {
fWriter.write(res);
fWriter.close();
fOut.close();
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to write contacts file: " +
e.toString());
}
} catch (java.io.FileNotFoundException e) {
Log.e("Baresip", "Failed to find contacts file: " +
e.toString());
}
String path = getApplicationContext().getFilesDir().getAbsolutePath() + "/contacts";
File file = new File(path);
Utils.putFileContents(file, editText.getText().toString());
Log.d("Baresip", "Updated contacts file");
MainActivity.contacts_remove();
updateContactsAndNames();
// MainActivity.CalleeAdapter.notifyDataSetChanged();
MainActivity.CalleeAdapter = new ArrayAdapter<String>
(this,android.R.layout.select_dialog_item, Names);
MainActivity.callee.setThreshold(2);
MainActivity.callee.setAdapter(MainActivity.CalleeAdapter);
i.putExtra("action", "save");
startActivity(i);
setResult(RESULT_OK, i);
finish();
return true;
case R.id.cancel:
i.putExtra("action", "cancel");
startActivity(i);
setResult(RESULT_OK, i);
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
static public void updateContactsAndNames() {
String path = MainActivity.mainActivityContext.getFilesDir().getAbsolutePath() + "/contacts";
File file = new File(path);
String[] lines = Utils.getFileContents(file).split("\n");
String name, uri;
Contacts.clear();
Names.clear();
for (String line : lines) {
line.trim();
if (line.startsWith("#") || line.length() == 0) continue;
String[] parts = line.split("\"");
if (parts.length != 3) {
Log.e("Baresip", "Invalid contacts line: " + line);
continue;
}
name = parts[1];
if (name.length() < 2) {
Log.e("Baresip", "Too short contact display name: " + name);
continue;
}
uri = parts[2].trim();
if (!uri.startsWith("<") || !uri.contains(">")) {
Log.e("Baresip", "Invalid contact uri: " + uri);
continue;
}
MainActivity.contact_add("\"" + name + "\" " + uri);
if (uri.indexOf(";access") > 0) continue;
uri = uri.substring(1, uri.indexOf(">"));
Log.d("Baresip", "Adding contact name/uri: " + name + "/" + uri);
Contacts.add(new Contact(name, uri));
Names.add(name);
}
}
static public String findContactURI(String name) {
for (Contact c : Contacts) {
if (c.getName().equals(name)) return c.getURI();
}
return name;
}
}

View File

@ -1,13 +1,18 @@
package com.tutpro.baresip;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.*;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.AutoCompleteTextView;
import android.view.*;
import android.util.Log;
import java.util.*;
@ -18,17 +23,19 @@ public class MainActivity extends AppCompatActivity {
static Context mainActivityContext;
static Boolean running = false;
static List <Account> accountList = new ArrayList<>();
static EditText callee;
static AutoCompleteTextView callee;
static RelativeLayout layout;
static Button callButton;
static ArrayList<Account> Accounts = new ArrayList<>();
static ArrayList<String> AoRs = new ArrayList<>();
static ArrayList<Integer> Images = new ArrayList<>();
static AccountSpinnerAdapter AccountAdapter = null;
static ArrayAdapter<String> CalleeAdapter = null;
static ArrayList<Call> In = new ArrayList<>();
static ArrayList<Call> Out = new ArrayList<>();
private static final int RECORD_AUDIO_PERMISSION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -73,8 +80,8 @@ public class MainActivity extends AppCompatActivity {
}
});
String[] assets = {"config", "accounts", "busy.wav", "callwaiting.wav", "error.wav",
"message.wav", "notfound.wav", "ring.wav", "ringback.wav"};
String[] assets = {"accounts", "contacts", "config", "busy.wav", "callwaiting.wav",
"error.wav", "message.wav", "notfound.wav", "ring.wav", "ringback.wav"};
final String path = mainActivityContext.getFilesDir().getPath();
Log.d("Baresip", "path is: " + path);
File file;
@ -93,9 +100,18 @@ public class MainActivity extends AppCompatActivity {
if (!file.exists()) {
Log.d("Baresip", "Copying asset " + a);
copyAsset(a, path + "/" + a);
} else {
Log.d("Baresip", "Asset " + a + " already copied");
}
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
Log.d("Baresip", "Baresip does not have RECORD_AUDIO permission");
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO}, RECORD_AUDIO_PERMISSION);
}
if (!running) {
Log.i("Baresip", "Starting Baresip with path " + path);
new Thread(new Runnable() {
@ -108,7 +124,12 @@ public class MainActivity extends AppCompatActivity {
layout = (RelativeLayout) findViewById(R.id.mainActivityLayout);
callee = (EditText)findViewById(R.id.callee);
callee = (AutoCompleteTextView)findViewById(R.id.callee);
EditContactsActivity.updateContactsAndNames();
CalleeAdapter = new ArrayAdapter<String>
(this,android.R.layout.select_dialog_item, EditContactsActivity.Names);
callee.setThreshold(2);
callee.setAdapter(CalleeAdapter);
callButton = (Button)findViewById(R.id.callButton);
callButton.setText("Call");
@ -117,7 +138,8 @@ public class MainActivity extends AppCompatActivity {
public void onClick(View v) {
String ua = ua_current();
if (callButton.getText().toString().equals("Call")) {
String uri = ((EditText) findViewById(R.id.callee)).getText().toString();
String callee = ((EditText) findViewById(R.id.callee)).getText().toString();
String uri = EditContactsActivity.findContactURI(callee);
if (!uri.startsWith("sip:")) uri = "sip:" + uri;
if (!uri.contains("@")) {
String aor = ua_aor(ua);
@ -152,6 +174,24 @@ public class MainActivity extends AppCompatActivity {
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case RECORD_AUDIO_PERMISSION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d("Baresip", "RECORD_AUDIO permission granted");
} else {
Log.d("Baresip", "RECORD_AUDIO permission NOT granted");
}
return;
}
default:
Log.e("Baresip", "Unknown permissions request code: " + requestCode);
}
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
@ -166,14 +206,15 @@ public class MainActivity extends AppCompatActivity {
startActivity(new Intent(MainActivity.this,
EditAccountsActivity.class));
return true;
case R.id.contacts:
startActivity(new Intent(MainActivity.this,
EditContactsActivity.class));
return true;
case R.id.config:
startActivity(new Intent(MainActivity.this,
EditConfigActivity.class));
return true;
//case R.id.contacts:
// startActivity(new Intent(MainActivity.this,
// EditContactsActivity.class));
//return true;
case R.id.about:
startActivity(new Intent(MainActivity.this,
AboutActivity.class));
@ -414,6 +455,7 @@ public class MainActivity extends AppCompatActivity {
final String peer_uri = call_peeruri(call);
Log.d("Baresip", "Incoming call " + ua + "/" + call + "/" +
peer_uri);
final Call new_call = new Call(ua, call, peer_uri, "Answer");
In.add(new_call);
Log.d("Baresip", "Current UA is " + ua_current());
@ -485,13 +527,14 @@ public class MainActivity extends AppCompatActivity {
public native String ua_aor(String ua);
public native Boolean ua_isregistered(long ua_ptr);
public native String ua_call(String ua);
public native String ua_prev_call(String ua);
public native String call_peeruri(String call);
public native String ua_current();
public static native void ua_current_set(String s);
public native String ua_connect(String s);
public native void ua_answer(String ua, String call);
public native void ua_hangup(String ua, String call, int code, String reason);
static public native void contacts_remove();
static public native void contact_add(String contact);
static {
System.loadLibrary("baresip");

View File

@ -0,0 +1,55 @@
package com.tutpro.baresip;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class Utils {
static public String getFileContents(File file) {
if (!file.exists()) {
Log.e("Baresip", "Failed to find file: " + file.getPath());
return "";
} else {
Log.e("Baresip", "Found file: " + file.getPath());
int length = (int) file.length();
byte[] bytes = new byte[length];
try {
FileInputStream in = new FileInputStream(file);
try {
in.read(bytes);
} finally {
in.close();
}
return new String(bytes);
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to read file: " + file.getPath() + ": " +
e.toString());
return "";
}
}
}
static public void putFileContents(File file, String contents) {
try {
FileOutputStream fOut =
new FileOutputStream(file.getAbsoluteFile(), false);
OutputStreamWriter fWriter = new OutputStreamWriter(fOut);
try {
fWriter.write(contents);
fWriter.close();
fOut.close();
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to put contents to file: " +
e.toString());
}
} catch (java.io.FileNotFoundException e) {
Log.e("Baresip", "Failed to find contents file: " +
e.toString());
}
}
}

View File

@ -12,7 +12,7 @@
<EditText
android:id="@+id/editText"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.tutpro.baresip.MainActivity"
tools:context=".MainActivity"
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -30,21 +30,21 @@
android:layout_below="@id/AoRList"
android:paddingTop="16dp"
android:paddingLeft="3dp"
android:textSize="20dp"
android:textSize="20sp"
android:textColor="@android:color/black"
android:text="Outgoing call to ..." >
</TextView>
<EditText
<AutoCompleteTextView
android:id="@+id/callee"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/outTitle"
android:inputType="textEmailAddress"
android:textSize="20dp"
android:textSize="20sp"
android:hint="Callee" >
<requestFocus />
</EditText>
<!-- <requestFocus /> -->
</AutoCompleteTextView>
<Button
android:id="@+id/callButton"

View File

@ -1,12 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/stop"
android:title="Stop" />
<item android:id="@+id/quit"
android:title="Quit" />
<item android:id="@+id/help"
android:title="Help" />
</menu>

View File

@ -3,11 +3,11 @@
<item android:id="@+id/accounts"
android:title="Accounts" />
<item android:id="@+id/config"
android:title="Config" />
<item android:id="@+id/contacts"
android:title="Contacts" />
<!-- <item android:id="@+id/contacts"
android:title="Contacts" /> -->
<item android:id="@+id/config"
android:title="Config" />
<item android:id="@+id/about"
android:title="About" />

View File

@ -5,7 +5,7 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 23
targetSdkVersion 25
versionCode 1
versionName "1.0"