summaryrefslogtreecommitdiff
path: root/pjsip-apps/src/swig/java
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip-apps/src/swig/java')
-rw-r--r--pjsip-apps/src/swig/java/Makefile124
-rw-r--r--pjsip-apps/src/swig/java/android/.classpath9
-rw-r--r--pjsip-apps/src/swig/java/android/.project33
-rw-r--r--pjsip-apps/src/swig/java/android/.settings/org.eclipse.jdt.core.prefs4
-rw-r--r--pjsip-apps/src/swig/java/android/AndroidManifest.xml44
-rw-r--r--pjsip-apps/src/swig/java/android/ic_launcher-web.pngbin0 -> 51394 bytes
-rw-r--r--pjsip-apps/src/swig/java/android/jni/Android.mk12
-rw-r--r--pjsip-apps/src/swig/java/android/jni/Application.mk1
-rw-r--r--pjsip-apps/src/swig/java/android/proguard-project.txt20
-rw-r--r--pjsip-apps/src/swig/java/android/project.properties14
-rw-r--r--pjsip-apps/src/swig/java/android/res/drawable-hdpi/ic_launcher.pngbin0 -> 7658 bytes
-rw-r--r--pjsip-apps/src/swig/java/android/res/drawable-mdpi/ic_launcher.pngbin0 -> 3777 bytes
-rw-r--r--pjsip-apps/src/swig/java/android/res/drawable-xhdpi/ic_launcher.pngbin0 -> 12516 bytes
-rw-r--r--pjsip-apps/src/swig/java/android/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 24777 bytes
-rw-r--r--pjsip-apps/src/swig/java/android/res/drawable/bkg.xml5
-rw-r--r--pjsip-apps/src/swig/java/android/res/layout/activity_call.xml41
-rw-r--r--pjsip-apps/src/swig/java/android/res/layout/activity_main.xml65
-rw-r--r--pjsip-apps/src/swig/java/android/res/layout/dlg_account_config.xml77
-rw-r--r--pjsip-apps/src/swig/java/android/res/layout/dlg_add_buddy.xml24
-rw-r--r--pjsip-apps/src/swig/java/android/res/menu/call.xml9
-rw-r--r--pjsip-apps/src/swig/java/android/res/menu/main.xml14
-rw-r--r--pjsip-apps/src/swig/java/android/res/values-sw600dp/dimens.xml8
-rw-r--r--pjsip-apps/src/swig/java/android/res/values-sw720dp-land/dimens.xml9
-rw-r--r--pjsip-apps/src/swig/java/android/res/values-v11/styles.xml11
-rw-r--r--pjsip-apps/src/swig/java/android/res/values-v14/styles.xml12
-rw-r--r--pjsip-apps/src/swig/java/android/res/values/colors.xml5
-rw-r--r--pjsip-apps/src/swig/java/android/res/values/dimens.xml7
-rw-r--r--pjsip-apps/src/swig/java/android/res/values/strings.xml9
-rw-r--r--pjsip-apps/src/swig/java/android/res/values/styles.xml20
-rw-r--r--pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java146
-rw-r--r--pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java497
-rw-r--r--pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java449
-rw-r--r--pjsip-apps/src/swig/java/sample.java140
-rw-r--r--pjsip-apps/src/swig/java/test.java17
34 files changed, 1826 insertions, 0 deletions
diff --git a/pjsip-apps/src/swig/java/Makefile b/pjsip-apps/src/swig/java/Makefile
new file mode 100644
index 00000000..1946891f
--- /dev/null
+++ b/pjsip-apps/src/swig/java/Makefile
@@ -0,0 +1,124 @@
+include ../../../../build.mak
+
+ifneq ($(findstring android,$(TARGET_NAME)),)
+ OS=android
+else
+ ifneq ($(findstring darwin,$(TARGET_NAME)),)
+ OS=darwin
+ endif
+endif
+
+OUT_DIR=output
+ifeq ($(OS),Windows_NT)
+ LIBPJSUA2_SO=$(OUT_DIR)/pjsua2.dll
+else
+ ifeq ($(OS),darwin)
+ LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.jnilib
+ else
+ ifeq ($(OS),android)
+ LIBPJSUA2_SO=android/libs/armeabi/libpjsua2.so
+ else
+ LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.so
+ endif
+ endif
+endif
+
+# Get JDK location
+ifeq ("$(JAVA_HOME)","")
+ # Get javac location to determine JDK location
+ JAVAC_PATH = $(shell which javac)
+ ifeq ("$(JAVAC_PATH)","")
+ $(error Cannot determine JDK location using 'which' command. Please define JAVA_HOME envvar)
+ endif
+
+ JAVAC_PATH := $(realpath $(JAVAC_PATH))
+ JAVA_BIN := $(dir $(JAVAC_PATH))
+ JAVA_HOME := $(patsubst %/bin/,%,$(JAVA_BIN))
+else
+ ifeq (exists, $(shell test -d $(JAVA_HOME)/bin && echo exists ))
+ JAVA_BIN := $(JAVA_HOME)/bin
+ else
+ JAVA_BIN := $(JAVA_HOME)
+ endif
+endif
+
+# OS specific
+ifeq ($(OS),Windows_NT)
+ MY_JNI_LDFLAGS = -L$(MY_JDK)/lib -Wl,--kill-at
+else
+ MY_JNI_CFLAGS = -fPIC
+ MY_JNI_LDFLAGS = -L$(MY_JDK)/lib
+ ifeq ($(OS),darwin)
+ MY_JNI_LDFLAGS := $(MY_JNI_LDFLAGS) -Wl,-soname,pjsua2.so
+ endif
+ ifeq ($(OS),android)
+ MY_JNI_CFLAGS := $(MY_JNI_CFLAGS) -D__ANDROID__
+ endif
+endif
+
+# Env settings, e.g: path to SWIG, JDK, java(.exe), javac(.exe)
+MY_SWIG = swig
+MY_JDK = $(JAVA_HOME)
+ifneq ($(findstring bin,$(JAVA_BIN)),)
+ MY_JAVA = $(MY_JDK)/bin/java
+ MY_JAVAC = $(MY_JDK)/bin/javac
+else
+ MY_JAVA = $(MY_JDK)/java
+ MY_JAVAC = $(MY_JDK)/javac
+endif
+MY_JNI_CFLAGS := $(MY_JNI_CFLAGS) -I$(MY_JDK)/include -I$(MY_JDK)/include/win32 \
+ -I$(MY_JDK)/include/linux -I.
+
+# Build settings
+MY_CFLAGS = $(PJ_CFLAGS) $(MY_JNI_CFLAGS)
+MY_LDFLAGS = $(PJ_LDFLAGS) -lpjsua2-$(TARGET_NAME) $(PJ_LDLIBS) $(MY_JNI_LDFLAGS)
+MY_PACKAGE_NAME = org.pjsip.pjsua2
+ifeq ($(OS),android)
+ MY_PACKAGE_PATH = android/src/$(subst .,/,$(MY_PACKAGE_NAME))
+else
+ MY_PACKAGE_PATH = $(OUT_DIR)/$(subst .,/,$(MY_PACKAGE_NAME))
+endif
+
+MY_APP_JAVA = android/src/$(subst .,/,$(MY_PACKAGE_NAME))/app/MyApp.java
+
+.PHONY: all java install uninstall
+
+all: $(LIBPJSUA2_SO) java
+
+$(LIBPJSUA2_SO): $(OUT_DIR)/pjsua2_wrap.o
+ $(PJ_CXX) -shared -o $(LIBPJSUA2_SO) $(OUT_DIR)/pjsua2_wrap.o $(MY_CFLAGS) $(MY_LDFLAGS)
+
+$(OUT_DIR)/pjsua2_wrap.o: $(OUT_DIR)/pjsua2_wrap.cpp Makefile
+ $(PJ_CXX) -c $(OUT_DIR)/pjsua2_wrap.cpp -o $(OUT_DIR)/pjsua2_wrap.o $(MY_CFLAGS) $(MY_LDFLAGS)
+
+$(OUT_DIR)/pjsua2_wrap.cpp: ../pjsua2.i ../symbols.i $(SRCS)
+ mkdir -p $(MY_PACKAGE_PATH)
+ swig $(SWIG_FLAGS) -java -package $(MY_PACKAGE_NAME) -outdir $(MY_PACKAGE_PATH) -o $(OUT_DIR)/pjsua2_wrap.cpp ../pjsua2.i
+
+clean distclean realclean:
+ rm -rf $(LIBPJSUA2_SO) $(OUT_DIR)/* $(MY_PACKAGE_PATH)/*.java $(MY_PACKAGE_PATH)/*.class
+
+java: $(MY_PACKAGE_PATH)/Error.class $(MY_PACKAGE_PATH)/test.class $(MY_PACKAGE_PATH)/sample.class
+
+$(MY_PACKAGE_PATH)/Error.class: $(MY_PACKAGE_PATH)/Error.java
+ $(MY_JAVAC) -d $(OUT_DIR) $(MY_PACKAGE_PATH)/*.java $(MY_APP_JAVA)
+
+$(MY_PACKAGE_PATH)/test.class: test.java
+ $(MY_JAVAC) -d $(OUT_DIR) -classpath "$(OUT_DIR)" test.java
+
+$(MY_PACKAGE_PATH)/sample.class: sample.java
+ $(MY_JAVAC) -d $(OUT_DIR) -classpath "$(OUT_DIR)" sample.java
+
+test:
+ @# Need to specify classpath and library path, alternatively, they can be set via
+ @# CLASSPATH and java.library.path env settings
+ $(MY_JAVA) -cp "$(OUT_DIR)" -Djava.library.path="$(OUT_DIR)" test
+
+sample:
+ @# Need to specify classpath and library path, alternatively, they can be set via
+ @# CLASSPATH and java.library.path env settings
+ $(MY_JAVA) -cp "$(OUT_DIR)" -Djava.library.path="$(OUT_DIR)" org.pjsip.pjsua2.app.sample
+
+install:
+uninstall:
+
diff --git a/pjsip-apps/src/swig/java/android/.classpath b/pjsip-apps/src/swig/java/android/.classpath
new file mode 100644
index 00000000..b76ec6cd
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/.classpath
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
diff --git a/pjsip-apps/src/swig/java/android/.project b/pjsip-apps/src/swig/java/android/.project
new file mode 100644
index 00000000..434a3408
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>Pjsua2</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/pjsip-apps/src/swig/java/android/.settings/org.eclipse.jdt.core.prefs b/pjsip-apps/src/swig/java/android/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..48ab4c6b
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/pjsip-apps/src/swig/java/android/AndroidManifest.xml b/pjsip-apps/src/swig/java/android/AndroidManifest.xml
new file mode 100644
index 00000000..5a9b0aef
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.pjsip.pjsua2.app"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="11"
+ android:targetSdkVersion="15" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="org.pjsip.pjsua2.app.MainActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.pjsip.pjsua2.app.CallActivity"
+ android:label="@string/title_activity_call" >
+ </activity>
+ </application>
+
+</manifest>
diff --git a/pjsip-apps/src/swig/java/android/ic_launcher-web.png b/pjsip-apps/src/swig/java/android/ic_launcher-web.png
new file mode 100644
index 00000000..a18cbb48
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/ic_launcher-web.png
Binary files differ
diff --git a/pjsip-apps/src/swig/java/android/jni/Android.mk b/pjsip-apps/src/swig/java/android/jni/Android.mk
new file mode 100644
index 00000000..94912baf
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/jni/Android.mk
@@ -0,0 +1,12 @@
+include ../../../../../build.mak
+
+LOCAL_PATH := $(PJDIR)/pjsip-apps/src/swig/java/android
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libpjsua2
+LOCAL_CFLAGS := $(APP_CFLAGS) -frtti -fexceptions
+LOCAL_LDFLAGS := $(APP_LDFLAGS)
+LOCAL_LDLIBS := $(APP_LDLIBS)
+LOCAL_SRC_FILES := ../output/pjsua2_wrap.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/pjsip-apps/src/swig/java/android/jni/Application.mk b/pjsip-apps/src/swig/java/android/jni/Application.mk
new file mode 100644
index 00000000..87124dd8
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/jni/Application.mk
@@ -0,0 +1 @@
+APP_STL := gnustl_static
diff --git a/pjsip-apps/src/swig/java/android/proguard-project.txt b/pjsip-apps/src/swig/java/android/proguard-project.txt
new file mode 100644
index 00000000..f2fe1559
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# 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 *;
+#}
diff --git a/pjsip-apps/src/swig/java/android/project.properties b/pjsip-apps/src/swig/java/android/project.properties
new file mode 100644
index 00000000..0840b4a0
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-15
diff --git a/pjsip-apps/src/swig/java/android/res/drawable-hdpi/ic_launcher.png b/pjsip-apps/src/swig/java/android/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000..288b6655
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/pjsip-apps/src/swig/java/android/res/drawable-mdpi/ic_launcher.png b/pjsip-apps/src/swig/java/android/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..6ae570b4
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/pjsip-apps/src/swig/java/android/res/drawable-xhdpi/ic_launcher.png b/pjsip-apps/src/swig/java/android/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..d4fb7cd9
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/pjsip-apps/src/swig/java/android/res/drawable-xxhdpi/ic_launcher.png b/pjsip-apps/src/swig/java/android/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..85a60815
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/pjsip-apps/src/swig/java/android/res/drawable/bkg.xml b/pjsip-apps/src/swig/java/android/res/drawable/bkg.xml
new file mode 100644
index 00000000..f5052332
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/drawable/bkg.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@color/pressed_color" />
+ <item android:drawable="@color/default_color" />
+</selector> \ No newline at end of file
diff --git a/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml b/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml
new file mode 100644
index 00000000..3745eb39
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/textViewPeer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:text="Peer URI"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:id="@+id/textViewCallState"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="Call state" />
+
+ <Button
+ android:id="@+id/buttonAccept"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:onClick="acceptCall"
+ android:text="Accept" />
+
+ <Button
+ android:id="@+id/buttonHangup"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:onClick="hangupCall"
+ android:text="Reject" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/pjsip-apps/src/swig/java/android/res/layout/activity_main.xml b/pjsip-apps/src/swig/java/android/res/layout/activity_main.xml
new file mode 100644
index 00000000..c63c0210
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ tools:context=".MainActivity" >
+
+ <ListView
+ android:id="@+id/listViewBuddy"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:listSelector="@drawable/bkg" >
+ </ListView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <ImageButton
+ android:id="@+id/buttonCall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:onClick="makeCall"
+ android:src="@android:drawable/ic_menu_call" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:text=" "/>
+
+ <ImageButton
+ android:id="@+id/buttonAddBuddy"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:onClick="addBuddy"
+ android:src="@android:drawable/ic_menu_add" />
+
+ <ImageButton
+ android:id="@+id/buttonEditBuddy"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:onClick="editBuddy"
+ android:src="@android:drawable/ic_menu_edit" />
+
+ <ImageButton
+ android:id="@+id/buttonDelBuddy"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:onClick="delBuddy"
+ android:src="@android:drawable/ic_menu_delete" />
+
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/pjsip-apps/src/swig/java/android/res/layout/dlg_account_config.xml b/pjsip-apps/src/swig/java/android/res/layout/dlg_account_config.xml
new file mode 100644
index 00000000..71111f14
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/layout/dlg_account_config.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TableLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:padding = "20dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/textViewInfo"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:paddingBottom="20dp"
+ android:textColor="#b0b0b0" >
+ </TextView>
+
+ <TableRow>
+ <TextView android:text="ID">
+ </TextView>
+
+ <EditText
+ android:id="@+id/editTextId"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:inputType="textUri" >
+
+ <requestFocus />
+ </EditText>
+ </TableRow>
+ <TableRow>
+ <TextView android:text="Registrar">
+ </TextView>
+ <EditText
+ android:id="@+id/editTextRegistrar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:inputType="textUri" >
+ </EditText>
+ </TableRow>
+ <TableRow>
+ <TextView android:text="Proxy">
+ </TextView>
+ <EditText
+ android:id="@+id/editTextProxy"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:inputType="textUri" >
+ </EditText>
+ </TableRow>
+ <TableRow>
+ <TextView android:text="Username">
+ </TextView>
+
+ <EditText
+ android:id="@+id/editTextUsername"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:inputType="text" >
+
+ </EditText>
+ </TableRow>
+ <TableRow>
+ <TextView android:text="Password">
+ </TextView>
+
+ <EditText
+ android:id="@+id/editTextPassword"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:inputType="textPassword" >
+
+ </EditText>
+ </TableRow>
+</TableLayout>
diff --git a/pjsip-apps/src/swig/java/android/res/layout/dlg_add_buddy.xml b/pjsip-apps/src/swig/java/android/res/layout/dlg_add_buddy.xml
new file mode 100644
index 00000000..f13e7005
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/layout/dlg_add_buddy.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TableLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:padding = "20dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TableRow>
+ <TextView android:text="Buddy URI">
+ </TextView>
+
+ <EditText
+ android:id="@+id/editTextUri"
+ android:layout_weight="1"
+ android:inputType="textUri" >
+ <requestFocus />
+ </EditText>
+ </TableRow>
+ <TableRow>
+ <CheckBox
+ android:id="@+id/checkBoxSubscribe"
+ android:layout_column="1"
+ android:text="Subscribe presence" />
+ </TableRow>
+</TableLayout>
diff --git a/pjsip-apps/src/swig/java/android/res/menu/call.xml b/pjsip-apps/src/swig/java/android/res/menu/call.xml
new file mode 100644
index 00000000..d122a4b7
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/menu/call.xml
@@ -0,0 +1,9 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never"
+ android:title="@string/action_settings"/>
+
+</menu>
diff --git a/pjsip-apps/src/swig/java/android/res/menu/main.xml b/pjsip-apps/src/swig/java/android/res/menu/main.xml
new file mode 100644
index 00000000..be94829a
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/menu/main.xml
@@ -0,0 +1,14 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/action_acc_config"
+ android:icon="@android:drawable/ic_menu_manage"
+ android:showAsAction="ifRoom"
+ android:title="Account Config"/>
+ <item
+ android:id="@+id/action_quit"
+ android:icon="@android:drawable/ic_menu_close_clear_cancel"
+ android:showAsAction="ifRoom"
+ android:title="Quit"/>
+
+</menu>
diff --git a/pjsip-apps/src/swig/java/android/res/values-sw600dp/dimens.xml b/pjsip-apps/src/swig/java/android/res/values-sw600dp/dimens.xml
new file mode 100644
index 00000000..c876987e
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values-sw600dp/dimens.xml
@@ -0,0 +1,8 @@
+<resources>
+
+ <!--
+ Customize dimensions originally defined in res/values/dimens.xml (such as
+ screen margins) for sw600dp devices (e.g. 7" tablets) here.
+ -->
+
+</resources>
diff --git a/pjsip-apps/src/swig/java/android/res/values-sw720dp-land/dimens.xml b/pjsip-apps/src/swig/java/android/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 00000000..0df30679
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,9 @@
+<resources>
+
+ <!--
+ Customize dimensions originally defined in res/values/dimens.xml (such as
+ screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
+ -->
+ <dimen name="activity_horizontal_margin">128dp</dimen>
+
+</resources>
diff --git a/pjsip-apps/src/swig/java/android/res/values-v11/styles.xml b/pjsip-apps/src/swig/java/android/res/values-v11/styles.xml
new file mode 100644
index 00000000..e3ef53d9
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/pjsip-apps/src/swig/java/android/res/values-v14/styles.xml b/pjsip-apps/src/swig/java/android/res/values-v14/styles.xml
new file mode 100644
index 00000000..94dd245c
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/pjsip-apps/src/swig/java/android/res/values/colors.xml b/pjsip-apps/src/swig/java/android/res/values/colors.xml
new file mode 100644
index 00000000..9ce61cf2
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values/colors.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="pressed_color">#B8F2F5</color>
+ <color name="default_color">#E8FEFF</color>
+</resources> \ No newline at end of file
diff --git a/pjsip-apps/src/swig/java/android/res/values/dimens.xml b/pjsip-apps/src/swig/java/android/res/values/dimens.xml
new file mode 100644
index 00000000..2e0e2ae4
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values/dimens.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
diff --git a/pjsip-apps/src/swig/java/android/res/values/strings.xml b/pjsip-apps/src/swig/java/android/res/values/strings.xml
new file mode 100644
index 00000000..2ee52b69
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">Pjsua2</string>
+ <string name="action_settings">Settings</string>
+ <string name="title_activity_call">Call</string>
+ <string name="hello_world">Hello world!</string>
+
+</resources>
diff --git a/pjsip-apps/src/swig/java/android/res/values/styles.xml b/pjsip-apps/src/swig/java/android/res/values/styles.xml
new file mode 100644
index 00000000..4ea93266
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources>
diff --git a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
new file mode 100644
index 00000000..48e1bad3
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
@@ -0,0 +1,146 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package org.pjsip.pjsua2.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.app.Activity;
+
+import org.pjsip.pjsua2.*;
+
+public class CallActivity extends Activity implements Handler.Callback {
+
+ public static Handler handler_;
+
+ private final Handler handler = new Handler(this);
+ private static CallInfo lastCallInfo;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_call);
+
+ handler_ = handler;
+ if (MainActivity.currentCall != null) {
+ try {
+ lastCallInfo = MainActivity.currentCall.getInfo();
+ updateCallState(lastCallInfo);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ } else {
+ updateCallState(lastCallInfo);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ handler_ = null;
+ }
+
+ public void acceptCall(View view) {
+ CallOpParam prm = new CallOpParam();
+ prm.setStatusCode(pjsip_status_code.PJSIP_SC_OK);
+ try {
+ MainActivity.currentCall.answer(prm);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ view.setVisibility(View.GONE);
+ }
+
+ public void hangupCall(View view) {
+ handler_ = null;
+ finish();
+
+ if (MainActivity.currentCall != null) {
+ CallOpParam prm = new CallOpParam();
+ prm.setStatusCode(pjsip_status_code.PJSIP_SC_DECLINE);
+ try {
+ MainActivity.currentCall.hangup(prm);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ MainActivity.currentCall = null;
+ }
+ }
+
+ @Override
+ public boolean handleMessage(Message m) {
+
+ if (m.what == MainActivity.MSG_TYPE.CALL_STATE) {
+
+ lastCallInfo = (CallInfo) m.obj;
+ updateCallState(lastCallInfo);
+
+ } else {
+
+ /* Message not handled */
+ return false;
+
+ }
+
+ return true;
+ }
+
+ private void updateCallState(CallInfo ci) {
+ TextView tvPeer = (TextView) findViewById(R.id.textViewPeer);
+ TextView tvState = (TextView) findViewById(R.id.textViewCallState);
+ Button buttonHangup = (Button) findViewById(R.id.buttonHangup);
+ Button buttonAccept = (Button) findViewById(R.id.buttonAccept);
+ String call_state = "";
+
+ if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAC) {
+ buttonAccept.setVisibility(View.GONE);
+ }
+
+ if (ci.getState().swigValue() < pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue())
+ {
+ if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAS) {
+ call_state = "Incoming call..";
+ /* Default button texts are already 'Accept' & 'Reject' */
+ } else {
+ buttonHangup.setText("Cancel");
+ call_state = ci.getStateText();
+ }
+ }
+ else if (ci.getState().swigValue() >= pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED.swigValue())
+ {
+ buttonAccept.setVisibility(View.GONE);
+ call_state = ci.getStateText();
+ if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) {
+ buttonHangup.setText("Hangup");
+ } else if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) {
+ buttonHangup.setText("OK");
+ call_state = "Call disconnected: " + ci.getLastReason();
+ MainActivity.currentCall = null;
+ }
+ }
+
+ tvPeer.setText(ci.getRemoteUri());
+ tvState.setText(call_state);
+ }
+}
diff --git a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java
new file mode 100644
index 00000000..34633f97
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MainActivity.java
@@ -0,0 +1,497 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package org.pjsip.pjsua2.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pjsip.pjsua2.*;
+
+public class MainActivity extends Activity implements Handler.Callback, MyAppObserver {
+ public static MyApp app = null;
+ public static MyCall currentCall = null;
+ public static MyAccount account = null;
+ public static AccountConfig accCfg = null;
+
+ private ListView buddyListView;
+ private SimpleAdapter buddyListAdapter;
+ private int buddyListSelectedIdx = -1;
+ ArrayList<Map<String, String>> buddyList;
+ private String lastRegStatus = "";
+
+ private final Handler handler = new Handler(this);
+ public class MSG_TYPE {
+ public final static int INCOMING_CALL = 1;
+ public final static int CALL_STATE = 2;
+ public final static int REG_STATE = 3;
+ public final static int BUDDY_STATE = 4;
+ }
+
+ private HashMap<String, String> putData(String uri, String status) {
+ HashMap<String, String> item = new HashMap<String, String>();
+ item.put("uri", uri);
+ item.put("status", status);
+ return item;
+ }
+
+ private void showCallActivity() {
+ Intent intent = new Intent(this, CallActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (app == null) {
+ app = new MyApp();
+ /* Wait for GDB to init */
+ if ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {}
+ }
+
+ app.init(this, getFilesDir().getAbsolutePath());
+ }
+
+ if (app.accList.size() == 0) {
+ accCfg = new AccountConfig();
+ accCfg.setIdUri("sip:localhost");
+ account = app.addAcc(accCfg);
+ } else {
+ account = app.accList.get(0);
+ accCfg = account.cfg;
+ }
+
+ buddyList = new ArrayList<Map<String, String>>();
+ for (int i = 0; i < account.buddyList.size(); i++) {
+ buddyList.add(putData(account.buddyList.get(i).cfg.getUri(),
+ account.buddyList.get(i).getStatusText()));
+ }
+
+ String[] from = { "uri", "status" };
+ int[] to = { android.R.id.text1, android.R.id.text2 };
+ buddyListAdapter = new SimpleAdapter(this, buddyList, android.R.layout.simple_list_item_2, from, to);
+
+ buddyListView = (ListView) findViewById(R.id.listViewBuddy);;
+ buddyListView.setAdapter(buddyListAdapter);
+ buddyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, final View view,
+ int position, long id)
+ {
+ view.setSelected(true);
+ buddyListSelectedIdx = position;
+ }
+ });
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_acc_config:
+ dlgAccountSetting();
+ break;
+
+ case R.id.action_quit:
+ Message m = Message.obtain(handler, 0);
+ m.sendToTarget();
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean handleMessage(Message m) {
+
+ if (m.what == 0) {
+
+ app.deinit();
+ finish();
+ Runtime.getRuntime().gc();
+ android.os.Process.killProcess(android.os.Process.myPid());
+
+ } else if (m.what == MSG_TYPE.CALL_STATE) {
+
+ CallInfo ci = (CallInfo) m.obj;
+
+ /* Forward the message to CallActivity */
+ if (CallActivity.handler_ != null) {
+ Message m2 = Message.obtain(CallActivity.handler_, MSG_TYPE.CALL_STATE, ci);
+ m2.sendToTarget();
+ }
+
+ if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
+ currentCall = null;
+
+ } else if (m.what == MSG_TYPE.BUDDY_STATE) {
+
+ MyBuddy buddy = (MyBuddy) m.obj;
+ int idx = account.buddyList.indexOf(buddy);
+ if (idx >= 0) {
+ buddyList.get(idx).put("status", buddy.getStatusText());
+ buddyListAdapter.notifyDataSetChanged();
+ // TODO: selection color/mark is gone after this,
+ // dont know how to return it back.
+ //buddyListView.setSelection(buddyListSelectedIdx);
+ //buddyListView.performItemClick(buddyListView, buddyListSelectedIdx,
+ // buddyListView.getItemIdAtPosition(buddyListSelectedIdx));
+
+ /* Return back Call activity */
+ notifyCallState(currentCall);
+ }
+
+ } else if (m.what == MSG_TYPE.REG_STATE) {
+
+ String msg_str = (String) m.obj;
+ lastRegStatus = msg_str;
+
+ } else if (m.what == MSG_TYPE.INCOMING_CALL) {
+
+ /* Incoming call */
+ final MyCall call = (MyCall) m.obj;
+ CallOpParam prm = new CallOpParam();
+
+ /* Only one call at anytime */
+ if (currentCall != null) {
+ prm.setStatusCode(pjsip_status_code.PJSIP_SC_BUSY_HERE);
+ try {
+ call.hangup(prm);
+ } catch (Exception e) {}
+ return true;
+ }
+
+ /* Answer with ringing */
+ prm.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING);
+ try {
+ call.answer(prm);
+ } catch (Exception e) {}
+
+ currentCall = call;
+ showCallActivity();
+
+ } else {
+
+ /* Message not handled */
+ return false;
+
+ }
+
+ return true;
+ }
+
+
+ private void dlgAccountSetting() {
+
+ LayoutInflater li = LayoutInflater.from(this);
+ View view = li.inflate(R.layout.dlg_account_config, null);
+
+ if (!lastRegStatus.isEmpty()) {
+ TextView tvInfo = (TextView)view.findViewById(R.id.textViewInfo);
+ tvInfo.setText("Last status: " + lastRegStatus);
+ }
+
+ AlertDialog.Builder adb = new AlertDialog.Builder(this);
+ adb.setView(view);
+ adb.setTitle("Account Settings");
+
+ final EditText etId = (EditText)view.findViewById(R.id.editTextId);
+ final EditText etReg = (EditText)view.findViewById(R.id.editTextRegistrar);
+ final EditText etProxy = (EditText)view.findViewById(R.id.editTextProxy);
+ final EditText etUser = (EditText)view.findViewById(R.id.editTextUsername);
+ final EditText etPass = (EditText)view.findViewById(R.id.editTextPassword);
+
+ etId. setText(accCfg.getIdUri());
+ etReg. setText(accCfg.getRegConfig().getRegistrarUri());
+ StringVector proxies = accCfg.getSipConfig().getProxies();
+ if (proxies.size() > 0)
+ etProxy.setText(proxies.get(0));
+ else
+ etProxy.setText("");
+ AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds();
+ if (creds.size() > 0) {
+ etUser. setText(creds.get(0).getUsername());
+ etPass. setText(creds.get(0).getData());
+ } else {
+ etUser. setText("");
+ etPass. setText("");
+ }
+
+ adb.setCancelable(false);
+ adb.setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,int id) {
+ String acc_id = etId.getText().toString();
+ String registrar = etReg.getText().toString();
+ String proxy = etProxy.getText().toString();
+ String username = etUser.getText().toString();
+ String password = etPass.getText().toString();
+
+ accCfg.setIdUri(acc_id);
+ accCfg.getRegConfig().setRegistrarUri(registrar);
+ AuthCredInfoVector creds = accCfg.getSipConfig().getAuthCreds();
+ creds.clear();
+ if (!username.isEmpty()) {
+ creds.add(new AuthCredInfo("Digest", "*", username, 0, password));
+ }
+ StringVector proxies = accCfg.getSipConfig().getProxies();
+ proxies.clear();
+ if (!proxy.isEmpty()) {
+ proxies.add(proxy);
+ }
+
+ /* Finally */
+ lastRegStatus = "";
+ try {
+ account.modify(accCfg);
+ } catch (Exception e) {}
+ }
+ });
+ adb.setNegativeButton("Cancel",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog ad = adb.create();
+ ad.show();
+ }
+
+
+ public void makeCall(View view) {
+ if (buddyListSelectedIdx == -1)
+ return;
+
+ /* Only one call at anytime */
+ if (currentCall != null) {
+ return;
+ }
+
+ HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx);
+ String buddy_uri = item.get("uri");
+
+ MyCall call = new MyCall(account, -1);
+ CallOpParam prm = new CallOpParam();
+ CallSetting opt = prm.getOpt();
+ opt.setAudioCount(1);
+ opt.setVideoCount(0);
+
+ try {
+ call.makeCall(buddy_uri, prm);
+ } catch (Exception e) {
+ currentCall = null;
+ return;
+ }
+
+ currentCall = call;
+ showCallActivity();
+ }
+
+ private void dlgAddEditBuddy(BuddyConfig initial) {
+ final BuddyConfig cfg = new BuddyConfig();
+ final BuddyConfig old_cfg = initial;
+ final boolean is_add = initial == null;
+
+ LayoutInflater li = LayoutInflater.from(this);
+ View view = li.inflate(R.layout.dlg_add_buddy, null);
+
+ AlertDialog.Builder adb = new AlertDialog.Builder(this);
+ adb.setView(view);
+
+ final EditText etUri = (EditText)view.findViewById(R.id.editTextUri);
+ final CheckBox cbSubs = (CheckBox)view.findViewById(R.id.checkBoxSubscribe);
+
+ if (is_add) {
+ adb.setTitle("Add Buddy");
+ } else {
+ adb.setTitle("Edit Buddy");
+ etUri. setText(initial.getUri());
+ cbSubs.setChecked(initial.getSubscribe());
+ }
+
+ adb.setCancelable(false);
+ adb.setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,int id) {
+ cfg.setUri(etUri.getText().toString());
+ cfg.setSubscribe(cbSubs.isChecked());
+
+ if (is_add) {
+ account.addBuddy(cfg);
+ buddyList.add(putData(cfg.getUri(), ""));
+ buddyListAdapter.notifyDataSetChanged();
+ buddyListSelectedIdx = -1;
+ } else {
+ if (!old_cfg.getUri().equals(cfg.getUri())) {
+ account.delBuddy(buddyListSelectedIdx);
+ account.addBuddy(cfg);
+ buddyList.remove(buddyListSelectedIdx);
+ buddyList.add(putData(cfg.getUri(), ""));
+ buddyListAdapter.notifyDataSetChanged();
+ buddyListSelectedIdx = -1;
+ } else if (old_cfg.getSubscribe() != cfg.getSubscribe()) {
+ MyBuddy bud = account.buddyList.get(buddyListSelectedIdx);
+ try {
+ bud.subscribePresence(cfg.getSubscribe());
+ } catch (Exception e) {}
+ }
+ }
+ }
+ });
+ adb.setNegativeButton("Cancel",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog ad = adb.create();
+ ad.show();
+ }
+
+ public void addBuddy(View view) {
+ dlgAddEditBuddy(null);
+ }
+
+ public void editBuddy(View view) {
+ if (buddyListSelectedIdx == -1)
+ return;
+
+ BuddyConfig old_cfg = account.buddyList.get(buddyListSelectedIdx).cfg;
+ dlgAddEditBuddy(old_cfg);
+ }
+
+ public void delBuddy(View view) {
+ if (buddyListSelectedIdx == -1)
+ return;
+
+ final HashMap<String, String> item = (HashMap<String, String>) buddyListView.getItemAtPosition(buddyListSelectedIdx);
+ String buddy_uri = item.get("uri");
+
+ DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ account.delBuddy(buddyListSelectedIdx);
+ buddyList.remove(item);
+ buddyListAdapter.notifyDataSetChanged();
+ buddyListSelectedIdx = -1;
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ break;
+ }
+ }
+ };
+
+ AlertDialog.Builder adb = new AlertDialog.Builder(this);
+ adb.setTitle(buddy_uri);
+ adb.setMessage("\nDelete this buddy?\n");
+ adb.setPositiveButton("Yes", ocl);
+ adb.setNegativeButton("No", ocl);
+ adb.show();
+ }
+
+
+ /*
+ * === MyAppObserver ===
+ *
+ * As we cannot do UI from worker thread, the callbacks mostly just send
+ * a message to UI/main thread.
+ */
+
+ public void notifyIncomingCall(MyCall call) {
+ Message m = Message.obtain(handler, MSG_TYPE.INCOMING_CALL, call);
+ m.sendToTarget();
+ }
+
+ public void notifyRegState(pjsip_status_code code, String reason, int expiration) {
+ String msg_str = "";
+ if (expiration == 0)
+ msg_str += "Unregistration";
+ else
+ msg_str += "Registration";
+
+ if (code.swigValue()/100 == 2)
+ msg_str += " successful";
+ else
+ msg_str += " failed: " + reason;
+
+ Message m = Message.obtain(handler, MSG_TYPE.REG_STATE, msg_str);
+ m.sendToTarget();
+ }
+
+ public void notifyCallState(MyCall call) {
+ if (currentCall == null || call.getId() != currentCall.getId())
+ return;
+
+ CallInfo ci;
+ try {
+ ci = call.getInfo();
+ } catch (Exception e) {
+ ci = null;
+ }
+ Message m = Message.obtain(handler, MSG_TYPE.CALL_STATE, ci);
+ m.sendToTarget();
+ }
+
+ public void notifyBuddyState(MyBuddy buddy) {
+ Message m = Message.obtain(handler, MSG_TYPE.BUDDY_STATE, buddy);
+ m.sendToTarget();
+ }
+
+ /* === end of MyAppObserver ==== */
+
+}
diff --git a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
new file mode 100644
index 00000000..7d7ab5d4
--- /dev/null
+++ b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
@@ -0,0 +1,449 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package org.pjsip.pjsua2.app;
+
+import java.io.File;
+import java.util.ArrayList;
+import org.pjsip.pjsua2.*;
+
+
+/* Interface to separate UI & engine a bit better */
+interface MyAppObserver {
+ abstract void notifyRegState(pjsip_status_code code, String reason, int expiration);
+ abstract void notifyIncomingCall(MyCall call);
+ abstract void notifyCallState(MyCall call);
+ abstract void notifyBuddyState(MyBuddy buddy);
+}
+
+
+class MyLogWriter extends LogWriter {
+ @Override
+ public void write(LogEntry entry) {
+ System.out.println(entry.getMsg());
+ }
+}
+
+
+class MyCall extends Call {
+ MyCall(MyAccount acc, int call_id) {
+ super(acc, call_id);
+ }
+
+ @Override
+ public void onCallState(OnCallStateParam prm) {
+ MyApp.observer.notifyCallState(this);
+ }
+
+ @Override
+ public void onCallMediaState(OnCallMediaStateParam prm) {
+ CallInfo ci;
+ try {
+ ci = getInfo();
+ } catch (Exception e) {
+ return;
+ }
+
+ CallMediaInfoVector cmiv = ci.getMedia();
+
+ for (int i = 0; i < cmiv.size(); i++) {
+ CallMediaInfo cmi = cmiv.get(i);
+ if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_AUDIO &&
+ (cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE ||
+ cmi.getStatus() == pjsua_call_media_status.PJSUA_CALL_MEDIA_REMOTE_HOLD))
+ {
+ // unfortunately, on Java too, the returned Media cannot be downcasted to AudioMedia
+ Media m = getMedia(i);
+ AudioMedia am = AudioMedia.typecastFromMedia(m);
+
+ // connect ports
+ try {
+ MyApp.ep.audDevManager().getCaptureDevMedia().startTransmit(am);
+ am.startTransmit(MyApp.ep.audDevManager().getPlaybackDevMedia());
+ } catch (Exception e) {
+ continue;
+ }
+ }
+ }
+ }
+}
+
+
+class MyAccount extends Account {
+ public ArrayList<MyBuddy> buddyList = new ArrayList<MyBuddy>();
+ public AccountConfig cfg;
+
+ MyAccount(AccountConfig config) {
+ super();
+ cfg = config;
+ }
+
+ public MyBuddy addBuddy(BuddyConfig bud_cfg)
+ {
+ /* Create Buddy */
+ MyBuddy bud = new MyBuddy(bud_cfg);
+ try {
+ bud.create(this, bud_cfg);
+ } catch (Exception e) {
+ bud = null;
+ }
+
+ if (bud != null) {
+ buddyList.add(bud);
+ if (bud_cfg.getSubscribe())
+ try {
+ bud.subscribePresence(true);
+ } catch (Exception e) {}
+ }
+
+ return bud;
+ }
+
+ public void delBuddy(MyBuddy buddy) {
+ buddyList.remove(buddy);
+ }
+
+ public void delBuddy(int index) {
+ buddyList.remove(index);
+ }
+
+ @Override
+ public void onRegState(OnRegStateParam prm) {
+ MyApp.observer.notifyRegState(prm.getCode(), prm.getReason(), prm.getExpiration());
+ }
+
+ @Override
+ public void onIncomingCall(OnIncomingCallParam prm) {
+ System.out.println("======== Incoming call ======== ");
+ MyCall call = new MyCall(this, prm.getCallId());
+ MyApp.observer.notifyIncomingCall(call);
+ }
+
+ @Override
+ public void onInstantMessage(OnInstantMessageParam prm) {
+ System.out.println("======== Incoming pager ======== ");
+ System.out.println("From : " + prm.getFromUri());
+ System.out.println("To : " + prm.getToUri());
+ System.out.println("Contact : " + prm.getContactUri());
+ System.out.println("Mimetype : " + prm.getContentType());
+ System.out.println("Body : " + prm.getMsgBody());
+ }
+}
+
+
+class MyBuddy extends Buddy {
+ public BuddyConfig cfg;
+
+ MyBuddy(BuddyConfig config) {
+ super();
+ cfg = config;
+ }
+
+ String getStatusText() {
+ BuddyInfo bi;
+
+ try {
+ bi = getInfo();
+ } catch (Exception e) {
+ return "?";
+ }
+
+ String status = "";
+ if (bi.getSubState() == pjsip_evsub_state.PJSIP_EVSUB_STATE_ACTIVE) {
+ if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_ONLINE) {
+ status = bi.getPresStatus().getStatusText();
+ if (status == null || status.isEmpty()) {
+ status = "Online";
+ }
+ } else if (bi.getPresStatus().getStatus() == pjsua_buddy_status.PJSUA_BUDDY_STATUS_OFFLINE) {
+ status = "Offline";
+ } else {
+ status = "Unknown";
+ }
+ }
+ return status;
+ }
+
+ @Override
+ public void onBuddyState() {
+ MyApp.observer.notifyBuddyState(this);
+ }
+
+}
+
+
+class MyAccountConfig {
+ public AccountConfig accCfg = new AccountConfig();
+ public ArrayList<BuddyConfig> buddyCfgs = new ArrayList<BuddyConfig>();
+
+ public void readObject(ContainerNode node) {
+ try {
+ ContainerNode acc_node = node.readContainer("Account");
+ accCfg.readObject(acc_node);
+ ContainerNode buddies_node = acc_node.readArray("buddies");
+ buddyCfgs.clear();
+ while (buddies_node.hasUnread()) {
+ BuddyConfig bud_cfg = new BuddyConfig();
+ bud_cfg.readObject(buddies_node);
+ buddyCfgs.add(bud_cfg);
+ }
+ } catch (Exception e) {}
+ }
+
+ public void writeObject(ContainerNode node) {
+ try {
+ ContainerNode acc_node = node.writeNewContainer("Account");
+ accCfg.writeObject(acc_node);
+ ContainerNode buddies_node = acc_node.writeNewArray("buddies");
+ for (int j = 0; j < buddyCfgs.size(); j++) {
+ buddyCfgs.get(j).writeObject(buddies_node);
+ }
+ } catch (Exception e) {}
+ }
+}
+
+
+class MyApp {
+ static {
+ System.loadLibrary("pjsua2");
+ System.out.println("Library loaded");
+ }
+
+ public static Endpoint ep = new Endpoint();
+ public static MyAppObserver observer;
+ public ArrayList<MyAccount> accList = new ArrayList<MyAccount>();
+
+ private ArrayList<MyAccountConfig> accCfgs = new ArrayList<MyAccountConfig>();
+ private EpConfig epConfig = new EpConfig();
+ private TransportConfig sipTpConfig = new TransportConfig();
+ private String appDir;
+
+ /* Maintain reference to log writer to avoid premature cleanup by GC */
+ private MyLogWriter logWriter;
+
+ private final String configName = "pjsua2.json";
+ private final int SIP_PORT = 6000;
+ private final int LOG_LEVEL = 4;
+
+ public void init(MyAppObserver obs, String app_dir) {
+ init(obs, app_dir, false);
+ }
+
+ public void init(MyAppObserver obs, String app_dir, boolean own_worker_thread) {
+ observer = obs;
+ appDir = app_dir;
+
+ /* Create endpoint */
+ try {
+ ep.libCreate();
+ } catch (Exception e) {
+ return;
+ }
+
+
+ /* Load config */
+ String configPath = appDir + "/" + configName;
+ File f = new File(configPath);
+ if (f.exists()) {
+ loadConfig(configPath);
+ } else {
+ /* Set 'default' values */
+ sipTpConfig.setPort(SIP_PORT);
+ }
+
+ /* Override log level setting */
+ epConfig.getLogConfig().setLevel(LOG_LEVEL);
+ epConfig.getLogConfig().setConsoleLevel(LOG_LEVEL);
+
+ /* Set log config. */
+ LogConfig log_cfg = epConfig.getLogConfig();
+ logWriter = new MyLogWriter();
+ log_cfg.setWriter(logWriter);
+ log_cfg.setDecor(log_cfg.getDecor() &
+ ~(pj_log_decoration.PJ_LOG_HAS_CR.swigValue() |
+ pj_log_decoration.PJ_LOG_HAS_NEWLINE.swigValue()));
+
+ /* Set ua config. */
+ UaConfig ua_cfg = epConfig.getUaConfig();
+ ua_cfg.setUserAgent("Pjsua2And" + ep.libVersion().getFull());
+ if (own_worker_thread) {
+ ua_cfg.setThreadCnt(0);
+ ua_cfg.setMainThreadOnly(true);
+ }
+
+ /* Init endpoint */
+ try {
+ ep.libInit(epConfig);
+ } catch (Exception e) {
+ return;
+ }
+
+ /* Create transports. */
+ try {
+ ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, sipTpConfig);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ try {
+ ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_TCP, sipTpConfig);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ /* Create accounts. */
+ for (int i = 0; i < accCfgs.size(); i++) {
+ MyAccountConfig my_cfg = accCfgs.get(i);
+ MyAccount acc = addAcc(my_cfg.accCfg);
+ if (acc == null)
+ continue;
+
+ /* Add Buddies */
+ for (int j = 0; j < my_cfg.buddyCfgs.size(); j++) {
+ BuddyConfig bud_cfg = my_cfg.buddyCfgs.get(j);
+ acc.addBuddy(bud_cfg);
+ }
+ }
+
+ /* Start. */
+ try {
+ ep.libStart();
+ } catch (Exception e) {
+ return;
+ }
+ }
+
+ public MyAccount addAcc(AccountConfig cfg) {
+ MyAccount acc = new MyAccount(cfg);
+ try {
+ acc.create(cfg);
+ } catch (Exception e) {
+ acc = null;
+ return null;
+ }
+
+ accList.add(acc);
+ return acc;
+ }
+
+ public void delAcc(MyAccount acc) {
+ accList.remove(acc);
+ }
+
+ private void loadConfig(String filename) {
+ JsonDocument json = new JsonDocument();
+
+ try {
+ /* Load file */
+ json.loadFile(filename);
+ ContainerNode root = json.getRootContainer();
+
+ /* Read endpoint config */
+ epConfig.readObject(root);
+
+ /* Read transport config */
+ ContainerNode tp_node = root.readContainer("SipTransport");
+ sipTpConfig.readObject(tp_node);
+
+ /* Read account configs */
+ accCfgs.clear();
+ ContainerNode accs_node = root.readArray("accounts");
+ while (accs_node.hasUnread()) {
+ MyAccountConfig acc_cfg = new MyAccountConfig();
+ acc_cfg.readObject(accs_node);
+ accCfgs.add(acc_cfg);
+ }
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ /* Force delete json now, as I found that Java somehow destroys it
+ * after lib has been destroyed and from non-registered thread.
+ */
+ json.delete();
+ }
+
+ private void buildAccConfigs() {
+ /* Sync accCfgs from accList */
+ accCfgs.clear();
+ for (int i = 0; i < accList.size(); i++) {
+ MyAccount acc = accList.get(i);
+ MyAccountConfig my_acc_cfg = new MyAccountConfig();
+ my_acc_cfg.accCfg = acc.cfg;
+
+ my_acc_cfg.buddyCfgs.clear();
+ for (int j = 0; j < acc.buddyList.size(); j++) {
+ MyBuddy bud = acc.buddyList.get(j);
+ my_acc_cfg.buddyCfgs.add(bud.cfg);
+ }
+
+ accCfgs.add(my_acc_cfg);
+ }
+ }
+
+ private void saveConfig(String filename) {
+ JsonDocument json = new JsonDocument();
+
+ try {
+ /* Write endpoint config */
+ json.writeObject(epConfig);
+
+ /* Write transport config */
+ ContainerNode tp_node = json.writeNewContainer("SipTransport");
+ sipTpConfig.writeObject(tp_node);
+
+ /* Write account configs */
+ buildAccConfigs();
+ ContainerNode accs_node = json.writeNewArray("accounts");
+ for (int i = 0; i < accCfgs.size(); i++) {
+ accCfgs.get(i).writeObject(accs_node);
+ }
+
+ /* Save file */
+ json.saveFile(filename);
+ } catch (Exception e) {}
+
+ /* Force delete json now, as I found that Java somehow destroys it
+ * after lib has been destroyed and from non-registered thread.
+ */
+ json.delete();
+ }
+
+ public void deinit() {
+ String configPath = appDir + "/" + configName;
+ saveConfig(configPath);
+
+ /* Try force GC to avoid late destroy of PJ objects as they should be
+ * deleted before lib is destroyed.
+ */
+ Runtime.getRuntime().gc();
+
+ /* Shutdown pjsua. Note that Endpoint destructor will also invoke
+ * libDestroy(), so this will be a test of double libDestroy().
+ */
+ try {
+ ep.libDestroy();
+ } catch (Exception e) {}
+
+ /* Force delete Endpoint here, to avoid deletion from a non-
+ * registered thread (by GC?).
+ */
+ ep.delete();
+ ep = null;
+ }
+}
diff --git a/pjsip-apps/src/swig/java/sample.java b/pjsip-apps/src/swig/java/sample.java
new file mode 100644
index 00000000..34d06b82
--- /dev/null
+++ b/pjsip-apps/src/swig/java/sample.java
@@ -0,0 +1,140 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package org.pjsip.pjsua2.app;
+
+import java.io.IOException;
+import org.pjsip.pjsua2.*;
+import org.pjsip.pjsua2.app.*;
+
+class MyObserver implements MyAppObserver {
+ private static MyCall currentCall = null;
+
+ @Override
+ public void notifyRegState(pjsip_status_code code, String reason, int expiration) {}
+
+ @Override
+ public void notifyIncomingCall(MyCall call) {
+ /* Auto answer. */
+ CallOpParam call_param = new CallOpParam();
+ call_param.setStatusCode(pjsip_status_code.PJSIP_SC_OK);
+ try {
+ currentCall = call;
+ currentCall.answer(call_param);
+ } catch (Exception e) {
+ System.out.println(e);
+ return;
+ }
+ }
+
+ @Override
+ public void notifyCallState(MyCall call) {
+ if (currentCall == null || call.getId() != currentCall.getId())
+ return;
+
+ CallInfo ci;
+ try {
+ ci = call.getInfo();
+ } catch (Exception e) {
+ ci = null;
+ }
+ if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
+ currentCall = null;
+ }
+
+ @Override
+ public void notifyBuddyState(MyBuddy buddy) {}
+}
+
+class MyShutdownHook extends Thread {
+ Thread thread;
+ MyShutdownHook(Thread thr) {
+ thread = thr;
+ }
+ public void run() {
+ thread.interrupt();
+ try {
+ thread.join();
+ } catch (Exception e) {
+ ;
+ }
+ }
+}
+
+public class sample {
+ private static MyApp app = new MyApp();
+ private static MyAppObserver observer = new MyObserver();
+ private static MyAccount account = null;
+ private static AccountConfig accCfg = null;
+
+ private static void runWorker() {
+ try {
+ app.init(observer, ".", true);
+ } catch (Exception e) {
+ System.out.println(e);
+ app.deinit();
+ System.exit(-1);
+ }
+
+ if (app.accList.size() == 0) {
+ accCfg = new AccountConfig();
+ accCfg.setIdUri("sip:localhost");
+ account = app.addAcc(accCfg);
+
+ accCfg.setIdUri("sip:301@pjsip.org");
+ AccountSipConfig sipCfg = accCfg.getSipConfig();
+ AuthCredInfoVector ciVec = sipCfg.getAuthCreds();
+ ciVec.add(new AuthCredInfo("Digest",
+ "*",
+ "301",
+ 0,
+ "pw301"));
+
+ StringVector proxy = sipCfg.getProxies();
+ proxy.add("sip:pjsip.org;transport=tcp");
+
+ AccountRegConfig regCfg = accCfg.getRegConfig();
+ regCfg.setRegistrarUri("sip:pjsip.org");
+ account = app.addAcc(accCfg);
+ } else {
+ account = app.accList.get(0);
+ accCfg = account.cfg;
+ }
+
+ try {
+ account.modify(accCfg);
+ } catch (Exception e) {}
+
+ while (!Thread.currentThread().isInterrupted()) {
+ MyApp.ep.libHandleEvents(10);
+ try {
+ Thread.currentThread().sleep(50);
+ } catch (InterruptedException ie) {
+ break;
+ }
+ }
+ app.deinit();
+ }
+
+ public static void main(String argv[]) {
+ Runtime.getRuntime().addShutdownHook(new MyShutdownHook(Thread.currentThread()));
+
+ runWorker();
+ }
+}
diff --git a/pjsip-apps/src/swig/java/test.java b/pjsip-apps/src/swig/java/test.java
new file mode 100644
index 00000000..f616460d
--- /dev/null
+++ b/pjsip-apps/src/swig/java/test.java
@@ -0,0 +1,17 @@
+import org.pjsip.pjsua2.*;
+
+public class test {
+ static {
+ System.loadLibrary("pjsua2");
+ System.out.println("Library loaded");
+ }
+
+ public static void main(String argv[]) {
+
+ AuthCredInfo cred = new AuthCredInfo();
+
+ cred.setRealm("Hello world");
+
+ System.out.println(cred.getRealm());
+ }
+}