first commit

This commit is contained in:
Juha Heinanen
2018-02-20 05:01:26 +02:00
commit ce52d1dbff
63 changed files with 2568 additions and 0 deletions

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
/.idea
local.properties
.DS_Store
*~
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
build
/captures
.externalNativeBuild

7
.google/packaging.yaml Normal file
View File

@ -0,0 +1,7 @@
status: PUBLISHED
technologies: [Android, NDK]
categories: [NDK]
languages: [C++, Java]
solutions: [Mobile]
github: googlesamples/android-ndk
license: apache2

13
.svnignore Normal file
View File

@ -0,0 +1,13 @@
.idea
local.properties
.DS_Store
*~
*.iml
.gradle
local.properties
.idea/workspace.xml
.idea/libraries
.DS_Store
build
captures
.externalNativeBuild

7
README.md Normal file
View File

@ -0,0 +1,7 @@
This is very basic Android Studio baresip project.
Includes PCMU/PCMA, speex, and opus codecs as well as ZRTP media
encapsulation.
The static libraries and include files in distribution directory have
been produced using https://github.com/alfredh/baresip-android.

34
app/build.gradle Normal file
View File

@ -0,0 +1,34 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion = 25
defaultConfig {
applicationId = 'com.tutpro.baresip'
minSdkVersion 21
targetSdkVersion 23
versionCode = 1
versionName = '1.0'
ndk {
abiFilters 'armeabi-v7a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support.constraint:constraint-layout:1.0.1'
}

17
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/gfan/dev/sdk_current/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tutpro.baresip"
android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<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_CONTACTS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize">
<!-- android:screenOrientation="portrait"> -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</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"
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=".EditConfigActivity"
android:label="Edit Config"
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=".EditContactsActivity"
android:label="Edit Contacts"
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=".AboutActivity"
android:label="About"
android:parentActivityName=".MainActivity"
android:theme="@style/AppTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.tutpro.baresip.MainActivity" />
</activity>
</application>
</manifest>

View File

@ -0,0 +1,34 @@
#
# SIP accounts - one account per line
#
# Displayname <sip:user:password@domain;uri-params>;addr-params
#
# uri-params:
# ;transport={udp,tcp,tls}
#
# addr-params:
# ;answermode={manual,early,auto}
# ;audio_codecs=speex/16000,pcma,...
# ;auth_user=username
# ;mediaenc={srtp,srtp-mand,srtp-mandf,dtls_srtp,zrtp}
# ;medianat={stun,turn,ice}
# ;outbound="sip:primary.example.com;transport=tcp"
# ;outbound2=sip:secondary.example.com
# ;ptime={10,20,30,40,...}
# ;regint=3600
# ;pubint=0 (publishing off)
# ;regq=0.5
# ;rtpkeep={zero,stun,dyna,rtcp}
# ;sipnat={outbound}
# ;stunuser=STUN/TURN/ICE-username
# ;stunpass=STUN/TURN/ICE-password
# ;stunserver=stun:[user:pass]@host[:port]
# ;video_codecs=h264,h263,...
#
# Examples:
#
# <sip:user:secret@domain.com;transport=tcp>
# <sip:user:secret@1.2.3.4;transport=tcp>
# <sip:user:secret@[2001:df8:0:16:216:6fff:fe91:614c]:5070;transport=tcp>
#
<sip:foo:password@test.tutpro.com>;auth_user=foo;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

Binary file not shown.

Binary file not shown.

200
app/src/main/assets/config Normal file
View File

@ -0,0 +1,200 @@
#
# baresip configuration
#
#------------------------------------------------------------------------------
# Core
poll_method epoll # poll, select, epoll ..
# SIP
sip_trans_bsize 128
#sip_listen 0.0.0.0:5060
#sip_certificate cert.pem
# Call
call_local_timeout 120
call_max_calls 4
# Audio
audio_player opensles,nil
audio_source opensles,nil
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
# Video
#video_source v4l2,/dev/video0
#video_display x11,nil
video_size 352x288
video_bitrate 500000
video_fps 25
video_fullscreen yes
# AVT - Audio/Video Transport
rtp_tos 184
#rtp_ports 10000-20000
#rtp_bandwidth 512-1024 # [kbit/s]
rtcp_enable yes
rtcp_mux no
jitter_buffer_delay 5-10 # frames
rtp_stats no
#rtp_timeout 60
# Network
#dns_server 10.0.0.1:53
#net_interface ^
# BFCP
#bfcp_proto udp
#------------------------------------------------------------------------------
# Modules
# UI Modules
#module stdio.so
#module cons.so
#module evdev.so
#module httpd.so
# Audio codec Modules (in order)
module opus.so
#module silk.so
#module amr.so
#module g7221.so
#module g722.so
#module g726.so
module g711.so
#module gsm.so
#module l16.so
module speex.so
#module bv32.so
#module mpa.so
#module codec2.so
#module ilbc.so
#module isac.so
# Audio filter Modules (in encoding order)
#module vumeter.so
#module sndfile.so
#module speex_aec.so
#module speex_pp.so
#module plc.so
# Audio driver Modules
module opensles.so
#module jack.so
#module portaudio.so
#module aubridge.so
#module aufile.so
# Video codec Modules (in order)
#module avcodec.so
#module vp8.so
#module vp9.so
#module h265.so
# Video filter Modules (in encoding order)
#module selfview.so
#module snapshot.so
#module swscale.so
#module vidinfo.so
# Video source modules
#module v4l.so
#module v4l2.so
#module v4l2_codec.so
#module x11grab.so
#module cairo.so
#module vidbridge.so
# Video display modules
#module directfb.so
#module x11.so
#module sdl2.so
#module fakevideo.so
# Audio/Video source modules
#module rst.so
#module gst1.so
#module gst_video1.so
# Media NAT modules
module stun.so
module turn.so
module ice.so
#module natpmp.so
# Media encryption modules
#module srtp.so
#module dtls_srtp.so
#module zrtp.so
#------------------------------------------------------------------------------
# Temporary Modules (loaded then unloaded)
module_tmp uuid.so
module_tmp account.so
#------------------------------------------------------------------------------
# Application Modules
module_app auloop.so
module_app contact.so
module_app debug_cmd.so
#module_app dtmfio.so
#module_app echo.so
#module_app gtk.so
module_app menu.so
#module_app mwi.so
#module_app natbd.so
#module_app presence.so
#module_app syslog.so
module_app vidloop.so
#------------------------------------------------------------------------------
# Module parameters
cons_listen 0.0.0.0:5555
http_listen 0.0.0.0:8000
evdev_device /dev/input/event0
# Speex codec parameters
speex_quality 7 # 0-10
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_agc_level 8000
# Opus codec parameters
opus_bitrate 28000 # 6000-510000
opus_cbr no
opus_inbandfec yes
# Selfview
#video_selfview window # {window,pip}
#selfview_size 64x64
# ICE
ice_turn no
ice_debug no
ice_nomination regular # {regular,aggressive}
ice_mode full # {full,lite}
# Menu
#redial_attempts 3 # Num or <inf>
#redial_delay 5 # Delay in seconds

View File

@ -0,0 +1,17 @@
#
# SIP contacts
#
# Displayname <sip:user@domain>;addr-params
#
# addr-params:
# ;presence={none,p2p}
# ;access={allow,block}
#
"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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,80 @@
#
# Copyright (C) The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
cmake_minimum_required(VERSION 3.4.1)
# configure import libs
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../distribution)
add_library(lib_crypto STATIC IMPORTED)
set_target_properties(lib_crypto PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
add_library(lib_ssl STATIC IMPORTED)
set_target_properties(lib_ssl PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a)
add_library(lib_re STATIC IMPORTED)
set_target_properties(lib_re PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/re/lib/${ANDROID_ABI}/libre.a)
add_library(lib_rem STATIC IMPORTED)
set_target_properties(lib_rem PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/rem/lib/${ANDROID_ABI}/librem.a)
add_library(lib_speex STATIC IMPORTED)
set_target_properties(lib_speex PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/speex/lib/${ANDROID_ABI}/libspeex.a)
add_library(lib_opus STATIC IMPORTED)
set_target_properties(lib_opus PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/opus/lib/${ANDROID_ABI}/libopus.a)
add_library(lib_bn STATIC IMPORTED)
set_target_properties(lib_bn PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/bn/lib/${ANDROID_ABI}/libbn.a)
add_library(lib_zrtp STATIC IMPORTED)
set_target_properties(lib_zrtp PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/zrtp/lib/${ANDROID_ABI}/libzrtp.a)
add_library(lib_baresip STATIC IMPORTED)
set_target_properties(lib_baresip PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/baresip/lib/${ANDROID_ABI}/libbaresip.a)
add_library(baresip SHARED baresip.c)
target_include_directories(baresip PRIVATE
${distribution_DIR}/openssl/include
${distribution_DIR}/re/include
${distribution_DIR}/rem/include
${distribution_DIR}/baresip/include)
target_link_libraries(baresip
android
OpenSLES
lib_baresip
lib_rem
lib_re
lib_ssl
lib_crypto
lib_speex
lib_opus
lib_zrtp
lib_bn
z
log)

458
app/src/main/cpp/baresip.c Normal file
View File

@ -0,0 +1,458 @@
#include <string.h>
#include <pthread.h>
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include <re.h>
#include <baresip.h>
#define LOGD(...) \
((void)__android_log_print(ANDROID_LOG_DEBUG, "Baresip", __VA_ARGS__))
#define LOGI(...) \
((void)__android_log_print(ANDROID_LOG_INFO, "Baresip", __VA_ARGS__))
#define LOGW(...) \
((void)__android_log_print(ANDROID_LOG_WARN, "Baresip", __VA_ARGS__))
#define LOGE(...) \
((void)__android_log_print(ANDROID_LOG_ERROR, "Baresip", __VA_ARGS__))
typedef struct tick_context {
JavaVM *javaVM;
jclass jniHelperClz;
jobject jniHelperObj;
jclass mainActivityClz;
jobject mainActivityObj;
pthread_mutex_t lock;
int done;
} TickContext;
TickContext g_ctx;
static void signal_handler(int sig)
{
static bool term = false;
if (term) {
mod_close();
exit(0);
}
term = true;
LOGI("terminated by signal (%d)\n", sig);
ua_stop_all(false);
}
static void ua_exit_handler(void *arg)
{
(void)arg;
LOGD("ua exited -- stopping main runloop\n");
re_cancel();
}
static const char *ua_event_reg_str(enum ua_event ev)
{
switch (ev) {
case UA_EVENT_REGISTERING: return "registering";
case UA_EVENT_REGISTER_OK: return "registered";
case UA_EVENT_REGISTER_FAIL: return "registering failed";
case UA_EVENT_UNREGISTERING: return "unregistering";
default: return "?";
}
}
static void ua_event_handler(struct ua *ua, enum ua_event ev,
struct call *call, const char *prm, void *arg)
{
const char *event;
char event_buf[256];
char ua_buf[256];
char call_buf[256];
LOGD("ua event (%s)\n", uag_event_str(ev));
switch (ev) {
case UA_EVENT_REGISTERING:
case UA_EVENT_UNREGISTERING:
case UA_EVENT_REGISTER_OK:
case UA_EVENT_REGISTER_FAIL:
re_snprintf(event_buf, sizeof event_buf, "%s", ua_event_reg_str(ev));
break;
case UA_EVENT_CALL_RINGING:
re_snprintf(event_buf, sizeof event_buf, "%s", "call ringing");
break;
case UA_EVENT_CALL_PROGRESS:
re_snprintf(event_buf, sizeof event_buf, "%s", "call progress");
break;
case UA_EVENT_CALL_ESTABLISHED:
re_snprintf(event_buf, sizeof event_buf, "%s", "call established");
break;
case UA_EVENT_CALL_INCOMING:
re_snprintf(event_buf, sizeof event_buf, "%s", "call incoming");
break;
case UA_EVENT_CALL_CLOSED:
re_snprintf(event_buf, sizeof event_buf, "%s", "call closed");
break;
case UA_EVENT_EXIT:
re_snprintf(event_buf, sizeof event_buf, "%s", "exit");
break;
default:
re_snprintf(event_buf, sizeof event_buf, "%s", "unknown event");
}
event = event_buf;
TickContext *pctx = (TickContext*)(&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 statusId = (*env)->GetMethodID(env, pctx->jniHelperClz,
"updateStatus",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
sprintf(ua_buf, "%lu", (unsigned long)ua);
jstring javaUA = (*env)->NewStringUTF(env, ua_buf);
sprintf(call_buf, "%lu", (unsigned long)call);
jstring javaCall = (*env)->NewStringUTF(env, call_buf);
jstring javaEvent = (*env)->NewStringUTF(env, event);
LOGD("sending ua/call %s/%s event %s\n", ua_buf, call_buf, event);
(*env)->CallVoidMethod(env, pctx->jniHelperObj, statusId, javaEvent, javaUA, javaCall);
(*env)->DeleteLocalRef(env, javaUA);
(*env)->DeleteLocalRef(env, javaCall);
(*env)->DeleteLocalRef(env, javaEvent);
}
#include <unistd.h>
static int pfd[2];
static pthread_t loggingThread;
static void *loggingFunction() {
ssize_t readSize;
char buf[128];
while((readSize = read(pfd[0], buf, sizeof buf - 1)) > 0) {
if(buf[readSize - 1] == '\n') {
--readSize;
}
buf[readSize] = 0;
LOGD("%s", buf);
}
return 0;
}
static int runLoggingThread() {
setvbuf(stdout, 0, _IOLBF, 0);
setvbuf(stderr, 0, _IONBF, 0);
pipe(pfd);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
if (pthread_create(&loggingThread, 0, loggingFunction, 0) == -1) {
return -1;
}
pthread_detach(loggingThread);
return 0;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
LOGD("Executing JNI_OnLoad\n");
memset(&g_ctx, 0, sizeof(g_ctx));
g_ctx.javaVM = vm;
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR; // JNI version not supported.
}
jclass clz = (*env)->FindClass(env, "com/tutpro/baresip/MainActivity");
g_ctx.jniHelperClz = (*env)->NewGlobalRef(env, clz);
jmethodID jniHelperCtor = (*env)->GetMethodID(env, g_ctx.jniHelperClz,
"<init>", "()V");
jobject handler = (*env)->NewObject(env, g_ctx.jniHelperClz,
jniHelperCtor);
g_ctx.jniHelperObj = (*env)->NewGlobalRef(env, handler);
g_ctx.done = 0;
g_ctx.mainActivityObj = NULL;
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_baresipStart(JNIEnv *env, jobject thiz, jstring javaPath)
{
int err;
const char *path = (*env)->GetStringUTFChars(env, javaPath, 0);
struct le *le;
runLoggingThread();
err = libre_init();
if (err)
goto out;
conf_path_set(path);
err = conf_configure();
if (err) {
LOGW("conf_configure() failed: (%d)\n", err);
goto out;
}
err = baresip_init(conf_config(), false);
if (err) {
LOGW("baresip_init() failed (%d)\n", err);
goto out;
}
play_set_path(baresip_player(), path);
err = ua_init("baresip v" BARESIP_VERSION " (" ARCH "/" OS ")",
true, true, true, false);
if (err) {
LOGE("ua_init() failed (%d)\n", err);
goto out;
}
uag_set_exit_handler(ua_exit_handler, NULL);
uag_event_register(ua_event_handler, NULL);
err = conf_modules();
if (err) {
LOGW("conf_modules() failed (%d)\n", err);
goto out;
}
TickContext *pctx = (TickContext*)(&g_ctx);
JavaVM *javaVM = pctx->javaVM;
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;
}
}
LOGD("Adding %u accounts", list_count(uag_list()));
char ua_buf[256];
struct ua *ua;
for (le = list_head(uag_list()); le; le = le->next) {
ua = le->data;
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->jniHelperClz, "addAccount",
"(Ljava/lang/String;)V");
(*env)->CallVoidMethod(env, pctx->jniHelperObj, accountId, javaUA);
(*env)->DeleteLocalRef(env, javaUA);
}
LOGI("Running main loop\n");
err = re_main(signal_handler);
out:
if (err) {
LOGE("error: (%d)\n", err);
ua_stop_all(true);
}
LOGD("closing upon main loop exit");
ua_close();
conf_close();
baresip_close();
mod_close();
libre_close();
// tmr_debug();
// mem_debug();
return;
}
JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_baresipStop(JNIEnv *env, jobject thiz)
{
LOGD("closing upon stop");
ua_stop_all(false);
ua_close();
// conf_close();
// baresip_close();
// mod_close();
// libre_close();
// tmr_debug();
// mem_debug();
return;
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_MainActivity_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);
if (strlen(native_ua) > 0)
return (*env)->NewStringUTF(env, ua_aor(ua));
else
return (*env)->NewStringUTF(env, "");
}
JNIEXPORT jboolean JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1isregistered(JNIEnv *env, jobject thiz, jlong ua_ptr)
{
struct ua *ua = (struct ua *)ua_ptr;
bool result;
result = ua_isregistered(ua);
if (ua == NULL) {
LOGD("ua_ptr is null\n");
} else {
LOGD("ua_ptr is NOT null\n");
}
return result;
}
JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1current_1set(JNIEnv *env, jobject thiz,
jstring javaAoR)
{
struct ua *new_current_ua;
const char *native_aor = (*env)->GetStringUTFChars(env, javaAoR, 0);
LOGD("running ua_current_set on %s\n", native_aor);
new_current_ua = uag_find_aor(native_aor);
uag_current_set(new_current_ua);
(*env)->ReleaseStringUTFChars(env, javaAoR, native_aor);
return;
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1current(JNIEnv *env, jobject thiz)
{
struct ua *current_ua = uag_current();
char ua_buf[256];
if (current_ua == NULL)
ua_buf[0] = '\0';
else
sprintf(ua_buf, "%lu", (unsigned long)current_ua);
return (*env)->NewStringUTF(env, ua_buf);
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1prev_1call(JNIEnv *env, jobject thiz, jstring javaUA)
{
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
struct call *call = ua_prev_call(ua);
char call_buf[256];
if (call == NULL)
call_buf[0] = '\0';
else
sprintf(call_buf, "%lu", (unsigned long)call);
return (*env)->NewStringUTF(env, call_buf);
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1call(JNIEnv *env, jobject thiz, jstring javaUA)
{
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
struct call *call = ua_call(ua);
char call_buf[256];
sprintf(call_buf, "%lu", (unsigned long)call);
return (*env)->NewStringUTF(env, call_buf);
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_MainActivity_call_1peeruri(JNIEnv *env, jobject thiz, jstring javaCall)
{
const char *native_call = (*env)->GetStringUTFChars(env, javaCall, 0);
struct call *call;
call = (struct call *)strtoul(native_call, NULL, 10);
(*env)->ReleaseStringUTFChars(env, javaCall, native_call);
return (*env)->NewStringUTF(env, call_peeruri(call));
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1connect(JNIEnv *env, jobject thiz,
jstring uri) {
struct call *call;
struct ua *ua;
int err;
const char *native_uri = (*env)->GetStringUTFChars(env, uri, 0);
char call_buf[256];
LOGD("connecting to %s\n", native_uri);
ua = uag_current();
if (ua != NULL) {
err = ua_connect(ua, &call, NULL, native_uri, NULL, VIDMODE_ON);
if (err) {
LOGW("connecting to %s failed with error %d\n", native_uri, err);
call_buf[0] = '\0';
} else {
sprintf(call_buf, "%lu", (unsigned long)call);
}
} else {
LOGE("no current ua\n");
call_buf[0] = '\0';
}
(*env)->ReleaseStringUTFChars(env, uri, native_uri);
return (*env)->NewStringUTF(env, call_buf);
}
JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1answer(JNIEnv *env, jobject thiz,
jstring javaUA, jstring javaCall) {
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
const char *native_call = (*env)->GetStringUTFChars(env, javaCall, 0);
LOGD("answering call %s/%s\n", native_ua, native_call);
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
struct call *call = (struct call *)strtoul(native_call, NULL, 10);
ua_answer(ua, call);
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
(*env)->ReleaseStringUTFChars(env, javaCall, native_call);
return;
}
JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_ua_1hangup(JNIEnv *env, jobject thiz,
jstring javaUA, jstring javaCall, jint code,
jstring reason) {
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
const char *native_call = (*env)->GetStringUTFChars(env, javaCall, 0);
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
struct call *call = (struct call *)strtoul(native_call, NULL, 10);
const uint16_t native_code = code;
const char *native_reason = (*env)->GetStringUTFChars(env, reason, 0);
LOGD("hanging up call %s/%s\n", native_ua, native_call);
// ua_hangup(ua, call, native_code, native_reason);
ua_hangup(uag_current(), NULL, 0, NULL);
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
(*env)->ReleaseStringUTFChars(env, javaCall, native_call);
(*env)->ReleaseStringUTFChars(env, reason, native_reason);
return;
}

View File

@ -0,0 +1,21 @@
package com.tutpro.baresip;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
public class AboutActivity extends AppCompatActivity {
private TextView aboutView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
aboutView = (TextView)findViewById(R.id.aboutText);
aboutView.setEnabled(false);
aboutView.setText(getString(R.string.aboutText));
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,104 @@
package com.tutpro.baresip;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.TextView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class EditContactsActivity extends AppCompatActivity {
private EditText editText;
private String path;
private File file;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_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());
editText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.textsize));
editText.setText(content, TextView.BufferType.EDITABLE);
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.edit_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
Intent i = new Intent(this, MainActivity.class);
switch (item.getItemId()) {
case R.id.save:
try {
FileOutputStream fOut =
new FileOutputStream(file.getAbsoluteFile(), false);
OutputStreamWriter fWriter = new OutputStreamWriter(fOut);
String res = editText.getText().toString();
try {
fWriter.write(res);
fWriter.close();
fOut.close();
} catch (java.io.IOException e) {
Log.e("Baresip", "Failed to write contacts file: " +
e.toString());
}
} catch (java.io.FileNotFoundException e) {
Log.e("Baresip", "Failed to find contacts file: " +
e.toString());
}
Log.d("Baresip", "Updated contacts file");
i.putExtra("action", "save");
startActivity(i);
return true;
case R.id.cancel:
i.putExtra("action", "cancel");
startActivity(i);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -0,0 +1,499 @@
package com.tutpro.baresip;
import android.content.Intent;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.*;
import android.widget.RelativeLayout.LayoutParams;
import android.view.*;
import android.util.Log;
import java.util.*;
import java.io.*;
import android.content.Context;
public class MainActivity extends AppCompatActivity {
static Context mainActivityContext;
static Boolean running = false;
static List <Account> accountList = new ArrayList<>();
static EditText 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 ArrayList<Call> In = new ArrayList<>();
static ArrayList<Call> Out = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityContext = getApplicationContext();
Spinner AoRSpinner = (Spinner) findViewById(R.id.AoRList);
Log.i("Baresip", "Setting AccountAdapter");
AccountAdapter = new AccountSpinnerAdapter(getApplicationContext(), AoRs, Images);
AoRSpinner.setAdapter(AccountAdapter);
AoRSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String aor = AoRs.get(position);
Log.i("Baresip", "Setting " + aor + " current");
ua_current_set(aor);
ArrayList<Call> out = uaCalls(Out, ua_current());
if (out.size() == 0) {
callee.setText("");
callButton.setText("Call");
} else {
callee.setText(out.get(0).getPeerURI());
callButton.setText(out.get(0).getStatus());
}
ArrayList<Call> in = uaCalls(In, ua_current());
int view_count = layout.getChildCount();
Log.d("Baresip", "View count is " + view_count);
if (view_count > 4) {
layout.removeViews(4, view_count - 4);
}
for (Call c: in) {
for (int call_index = 0; call_index < In.size(); call_index++) {
addCallViews(c,(call_index + 1) * 10);
}
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Log.i("Baresip", "Nothing selected");
}
});
String[] assets = {"config", "accounts", "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;
file = new File(path);
if (!file.exists()) {
Log.d("Baresip", "Creating baresip directory");
try {
new File(path).mkdirs();
} catch (Error e) {
Log.e("Baresip", "Failed to create directory: " +
e.toString());
}
}
for (String a : assets) {
file = new File(path + "/" + a);
if (!file.exists()) {
Log.d("Baresip", "Copying asset " + a);
copyAsset(a, path + "/" + a);
}
}
if (!running) {
Log.i("Baresip", "Starting Baresip with path " + path);
new Thread(new Runnable() {
public void run() {
baresipStart(path);
}
}).start();
running = true;
}
layout = (RelativeLayout) findViewById(R.id.mainActivityLayout);
callee = (EditText)findViewById(R.id.callee);
callButton = (Button)findViewById(R.id.callButton);
callButton.setText("Call");
callButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String ua = ua_current();
if (callButton.getText().toString().equals("Call")) {
String uri = ((EditText) findViewById(R.id.callee)).getText().toString();
if (!uri.startsWith("sip:")) uri = "sip:" + uri;
if (!uri.contains("@")) {
String aor = ua_aor(ua);
String host = aor.substring(aor.indexOf("@") + 1);
uri = uri + "@" + host;
}
((EditText) findViewById(R.id.callee)).setText(uri);
Log.i("Baresip", "Calling " + uri);
String call = ua_connect(uri);
if (!call.equals("")) {
Log.i("Baresip", "Adding outgoing call " + ua + "/" + call +
"/" + uri);
Out.add(new Call(ua, call, uri,"Cancel"));
callButton.setText("Cancel");
}
} else {
Log.i("Baresip", "Hanging up " +
((EditText) findViewById(R.id.callee)).getText());
ua_hangup(ua, "", 486, "Rejected");
}
}
});
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.d("Baresip", "Screen orientation change to landscape");
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Log.d("Baresip", "Screen orientation change to portrait");
}
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
Intent i = new Intent(this, MainActivity.class);
switch (item.getItemId()) {
case R.id.accounts:
startActivity(new Intent(MainActivity.this,
EditAccountsActivity.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));
return true;
case R.id.quit:
if (running) {
Log.d("Baresip", "Stopping");
baresipStop();
Accounts.clear();
AoRs.clear();
Images.clear();
running = false;
}
finish();
System.exit(0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public ArrayList<String> aorStatusList() {
ArrayList<String> res = new ArrayList<>();
for (Account a : Accounts) {
res.add(a.getAoR() + " (" + a.getStatus() + ")");
}
return res;
}
public void addAccount(String ua) {
String aor = ua_aor(ua);
Log.d("Baresip", "Adding account " + ua + " with AoR " + aor);
Accounts.add(new Account(ua, aor));
AoRs.add(aor + " ()");
Images.add(R.drawable.yellow);
runOnUiThread(new Runnable() {
@Override
public void run() {
AccountAdapter.notifyDataSetChanged();
}
});
}
private void copyAsset(String asset, String path) {
try {
AssetManager assetManager = getAssets();
InputStream is = assetManager.open(asset);
OutputStream os = new FileOutputStream(path);
byte [] buffer = new byte[512];
int byteRead;
while ((byteRead = is.read(buffer)) != -1) {
os.write(buffer, 0, byteRead);
}
} catch (IOException e) {
Log.e("Baresip", "Failed to read asset " + asset + ": " +
e.toString());
}
}
private void addCallViews(final Call call, int id) {
Log.d("Baresip", "Creating new Incoming textview at " + id);
TextView caller_heading = new TextView(mainActivityContext);
caller_heading.setText("Incoming call from ...");
caller_heading.setTextColor(Color.BLACK);
caller_heading.setTextSize(20);
caller_heading.setPadding(10, 20, 0, 0);
caller_heading.setId(id);
LayoutParams heading_params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
if (id == 10)
heading_params.addRule(RelativeLayout.BELOW, callButton.getId());
else
heading_params.addRule(RelativeLayout.BELOW,id - 10 + 3);
caller_heading.setLayoutParams(heading_params);
layout.addView(caller_heading);
TextView caller_uri = new TextView(mainActivityContext);
caller_uri.setText(In.get(In.size() - 1).getPeerURI());
caller_uri.setTextColor(Color.GREEN);
caller_uri.setTextSize(20);
caller_uri.setPadding(10, 10, 0, 10);
Log.d("Baresip", "Creating new caller textview at " + (id + 1));
caller_uri.setId(id + 1);
LayoutParams caller_uri_params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
caller_uri_params.addRule(RelativeLayout.BELOW, id);
caller_uri.setLayoutParams(caller_uri_params);
layout.addView(caller_uri);
Button answer_button = new Button(mainActivityContext);
answer_button.setText("Answer");
answer_button.setBackgroundResource(android.R.drawable.btn_default);
answer_button.setTextColor(Color.BLACK);
Log.d("Baresip", "Creating new answer button at " + (id + 2));
answer_button.setId(id + 2);
answer_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String call_ua = call.getUA();
String call_call = call.getCall();
switch (((Button)v).getText().toString()) {
case "Answer":
Log.i("Baresip", "UA " + call_ua + " accepting incoming call " +
call_call);
ua_answer(call_ua, call_call);
final int final_in_index = callIndex(In, call_ua, call_call);
if (final_in_index >= 0) {
Log.d("Baresip", "Changing answer button text to Hangup");
runOnUiThread(new Runnable() {
@Override
public void run() {
final int answer_id = (final_in_index + 1) * 10 + 2;
Button answer_button = (Button)layout.findViewById(answer_id);
answer_button.setText("Hangup");
Button reject_button = (Button)layout.findViewById(answer_id + 1);
reject_button.setEnabled(false);
}
});
}
break;
case "Hangup":
Log.i("Baresip", "UA " + call_ua + " hanging up call " +
call_call);
ua_hangup(call_ua, call_call,200, "OK");
break;
default:
Log.e("Baresip", "Invalid answer button text: " +
((Button)v).getText().toString());
break;
}
}
});
LayoutParams answer_button_params = new LayoutParams(200,
LayoutParams.WRAP_CONTENT);
answer_button_params.addRule(RelativeLayout.BELOW, id + 1);
answer_button_params.setMargins(3, 10, 0, 0);
answer_button.setLayoutParams(answer_button_params);
layout.addView(answer_button);
Button reject_button = new Button(mainActivityContext);
reject_button.setText("Reject");
reject_button.setBackgroundResource(android.R.drawable.btn_default);
reject_button.setTextColor(Color.BLACK);
Log.d("Baresip", "Creating new reject button at " + (id + 3));
reject_button.setId(id + 3);
reject_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("Baresip", "UA " + call.getUA() +
" rejecting incoming call " + call.getCall());
ua_hangup(call.getUA(), call.getCall(), 486, "Rejected");
}
});
LayoutParams reject_button_params = new LayoutParams(200,
LayoutParams.WRAP_CONTENT);
reject_button_params.addRule(RelativeLayout.BELOW, id + 1);
reject_button_params.setMargins(225, 10, 0, 0);
reject_button.setLayoutParams(reject_button_params);
layout.addView(reject_button);
}
private int callIndex(ArrayList<Call> calls, String ua, String call) {
for (int i = 0; i < calls.size(); i++) {
if (calls.get(i).getUA().equals(ua) && calls.get(i).getCall().equals(call))
return i;
}
return -1;
}
private ArrayList<Call> uaCalls(ArrayList<Call> calls, String ua) {
ArrayList<Call> result = new ArrayList<>();
for (int i = 0; i < calls.size(); i++) {
if (calls.get(i).getUA().equals(ua)) result.add(calls.get(i));
}
return result;
}
private void updateStatus(String event, final String ua, final String call) {
String aor = ua_aor(ua);
int index, call_index;
Log.d("Baresip", "Handling event " + event + " for " + ua + "/" + call + "/" +
aor);
for (index = 0; index < Accounts.size(); index++) {
if (Accounts.get(index).getAoR().equals(aor)) {
Log.d("Baresip", "Found AoR at index " + index);
switch (event) {
case "registering":
case "unregistering":
// Log.d("Baresip", "Setting status to yellow");
break;
case "registered":
Log.d("Baresip", "Setting status to green");
Accounts.get(index).setStatus("OK");
AoRs.set(index, aor);
Images.set(index, R.drawable.green);
runOnUiThread(new Runnable() {
@Override
public void run() {
AccountAdapter.notifyDataSetChanged();
}
});
break;
case "registering failed":
Log.d("Baresip", "Setting status to red");
Accounts.get(index).setStatus("FAIL");
AoRs.set(index, aor);
Images.set(index, R.drawable.red);
runOnUiThread(new Runnable() {
@Override
public void run() {
AccountAdapter.notifyDataSetChanged();
}
});
break;
case "call ringing":
break;
case "call established":
Log.d("Baresip", "Out call number is " + Out.size());
int out_index = callIndex(Out, ua, call);
if (out_index >= 0) {
Log.d("Baresip", "Changing call button text to Hangup");
Out.get(out_index).setStatus("Hangup");
if (ua.equals(ua_current())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
callButton.setText("Hangup");
}
});
}
break;
}
Log.e("Baresip", "Unknown call " + ua + "/" + call +
" established");
break;
case "call incoming":
final String peer_uri = call_peeruri(call);
Log.d("Baresip", "Incoming call " + ua + "/" + call + "/" +
peer_uri);
final Call new_call = new Call(ua, call, peer_uri, "Answer");
In.add(new_call);
if (ua.equals(ua_current())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
addCallViews(new_call, In.size() * 10);
}
});
}
break;
case "call closed":
call_index = callIndex(In, ua, call);
if (call_index != -1) {
Log.d("Baresip", "Removing inbound call " + ua + "/" +
call + "/" + In.get(index).getPeerURI());
final int view_id = (call_index + 1) * 10;
final int remove_count = In.size() - call_index;
final int final_call_index = call_index;
In.remove(call_index);
Log.d("Baresip", "Current UA is " + ua_current());
if (ua.equals(ua_current())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
View caller_heading = layout.findViewById(view_id);
int view_index = layout.indexOfChild(caller_heading);
Log.d("Baresip", "Index of caller heading is " +
view_index);
layout.removeViews(view_index, 4 * remove_count);
for (int i = final_call_index; i < In.size(); i++) {
addCallViews(In.get(i), (i + 1) * 10);
}
}
});
}
break;
}
call_index = callIndex(Out, ua, call);
if (call_index != -1) {
Log.d("Baresip", "Removing called call " + ua + "/" +
call + "/" + Out.get(index).getPeerURI());
Out.remove(call_index);
if (ua.equals(ua_current())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
callButton.setText("Call");
callButton.setEnabled(true);
}
});
}
break;
}
Log.e("Baresip", "Unknown call " + ua + "/" + call +
" closed");
break;
default:
Log.d("Baresip", "Unknown event '" + event + "'");
break;
}
}
}
}
public native void baresipStart(String path);
public native void baresipStop();
public 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 {
System.loadLibrary("baresip");
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#d3d3d3" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/spinnerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TableRow
android:id="@+id/spinnerRow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dip" >
<ImageView
android:id="@+id/spinnerImage"
android:contentDescription="@string/app_name" />
<TextView
android:id="@+id/spinnerText"
android:textSize="18dp"
android:paddingLeft="6dip"
android:textColor="@android:color/black" />
</TableRow>
</TableLayout>

View File

@ -0,0 +1,17 @@
<?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.AboutActivity">
<EditText
android:id="@+id/aboutText"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>

View File

@ -0,0 +1,18 @@
<?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.EditAccountsActivity">
<EditText
android:id="@+id/editAccounts"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>

View File

@ -0,0 +1,18 @@
<?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.EditConfigActivity">
<EditText
android:id="@+id/editConfig"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>

View File

@ -0,0 +1,18 @@
<?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.EditContactsActivity">
<EditText
android:id="@+id/editText"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Hello World!" />
</RelativeLayout>

View File

@ -0,0 +1,60 @@
<?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"
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<RelativeLayout
android:id="@+id/mainActivityLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<Spinner
android:id="@+id/AoRList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/btn_dropdown"
android:spinnerMode="dropdown"/>
<TextView
android:id="@+id/outTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/AoRList"
android:paddingTop="16dp"
android:paddingLeft="3dp"
android:textSize="20dp"
android:textColor="@android:color/black"
android:text="Outgoing call to ..." >
</TextView>
<EditText
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:hint="Callee" >
<requestFocus />
</EditText>
<Button
android:id="@+id/callButton"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:background="@android:drawable/btn_default"
android:layout_below="@id/callee"
android:text="@id/callee" >
</Button>
</RelativeLayout>
</ScrollView>

View File

@ -0,0 +1,12 @@
<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

@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/save"
android:title="Save" />
<item android:id="@+id/cancel"
android:title="Cancel" />
</menu>

View File

@ -0,0 +1,18 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<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/about"
android:title="About" />
<item android:id="@+id/quit"
android:title="Quit" />
</menu>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View File

@ -0,0 +1,6 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="fab_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="textsize">12sp</dimen>
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">baresip</string>
<string name="title_activity_edit">EditActivity</string>
<string name="title_activity_edit_accounts">EditAccounts</string>
<string name="aboutText">
Baresip Android application\n\n
Work in progress\n\n
Juha Heinanen jh@tutpro.com\n\n
</string>
<string name="noAccounts">No accounts</string>
<string name="emptyString"></string>
</resources>

View File

@ -0,0 +1,20 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

23
build.gradle Normal file
View File

@ -0,0 +1,23 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

40
gen-libs/build.gradle Normal file
View File

@ -0,0 +1,40 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
minSdkVersion 14
targetSdkVersion 17
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
arguments '-DANDROID_PLATFORM=android-17',
'-DANDROID_TOOLCHAIN=clang'
// explicitly build libs
// targets 're', 'rem', 'baresip'
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.4.0'
}

17
gen-libs/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/gfan/dev/sdk_current/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tutpro.buildlibs">
<application android:allowBackup="true" android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">BuildLibs</string>
</resources>

18
gradle.properties Normal file
View File

@ -0,0 +1,18 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Thu Jan 18 06:24:19 EET 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

160
gradlew vendored Executable file
View File

@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored Normal file
View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

11
settings.gradle Normal file
View File

@ -0,0 +1,11 @@
include ':app'
// The following is just for generating libs only.
// To use:
// uncomment out this line
// make sure uncomment out the one inside app/build.gradle to enable dependency
// build the app in Android Studio or command line
// Comment out this line and the one inside app/build.gradle again
// include ':gen-libs'