Index: /pjproject/trunk/pjsip-apps/src/swig/java/Makefile
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/Makefile	(revision 5501)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/Makefile	(revision 5502)
@@ -22,5 +22,5 @@
   else
     ifeq ($(OS),android)
-      LIBPJSUA2_SO=android/libs/armeabi/libpjsua2.so
+      LIBPJSUA2_SO=android/app/src/main/jniLibs/armeabi/libpjsua2.so
     else
       LIBPJSUA2_SO=$(OUT_DIR)/libpjsua2.so
@@ -150,10 +150,10 @@
 MY_PACKAGE_NAME	 := org.pjsip.pjsua2
 ifeq ($(OS),android)
-  MY_PACKAGE_PATH  := android/src/$(subst .,/,$(MY_PACKAGE_NAME))
+  MY_PACKAGE_PATH  := android/app/src/main/java/$(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
+MY_APP_JAVA := android/app/src/main/java/$(subst .,/,$(MY_PACKAGE_NAME))/app/MyApp.java
 
 .PHONY: all java install uninstall
Index: project/trunk/pjsip-apps/src/swig/java/android/.classpath
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/.classpath	(revision 5501)
+++ 	(revision )
@@ -1,9 +1,0 @@
-<?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>
Index: project/trunk/pjsip-apps/src/swig/java/android/.project
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/.project	(revision 5501)
+++ 	(revision )
@@ -1,33 +1,0 @@
-<?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>
Index: project/trunk/pjsip-apps/src/swig/java/android/AndroidManifest.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/AndroidManifest.xml	(revision 5501)
+++ 	(revision )
@@ -1,48 +1,0 @@
-<?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.CAMERA" />
-    <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" />
-    
-    <uses-feature android:glEsVersion="0x00020000" android:required="false" />
-
-    <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:configChanges="orientation|keyboardHidden|screenSize"
-            android:label="@string/title_activity_call" >
-        </activity>
-    </application>
-
-</manifest>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/build.gradle
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/build.gradle	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/build.gradle	(revision 5502)
@@ -0,0 +1,23 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 15
+    buildToolsVersion "23.0.3"
+
+    defaultConfig {
+        applicationId "org.pjsip.pjsua2.app"
+        minSdkVersion 11
+        targetSdkVersion 15
+
+        ndk {
+            moduleName "libpjsua2"
+        }
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+        }
+    }
+}
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/AndroidManifest.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/AndroidManifest.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/AndroidManifest.xml	(revision 5502)
@@ -0,0 +1,48 @@
+<?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.CAMERA" />
+    <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" />
+    
+    <uses-feature android:glEsVersion="0x00020000" android:required="false" />
+
+    <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:configChanges="orientation|keyboardHidden|screenSize"
+            android:label="@string/title_activity_call" >
+        </activity>
+    </application>
+
+</manifest>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/PjCamera.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/PjCamera.java	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/PjCamera.java	(revision 5502)
@@ -0,0 +1,210 @@
+/* $Id: PjCamera.java 5019 2015-03-23 06:35:45Z nanang $ */
+/*
+ * Copyright (C) 2015 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;
+
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.util.Log;
+import android.view.SurfaceView;
+import android.view.SurfaceHolder;
+
+import java.io.IOException;
+
+public class PjCamera implements Camera.PreviewCallback, SurfaceHolder.Callback
+{
+    private final String TAG = "PjCamera";
+
+    public class Param {
+	public int width;
+	public int height;
+	public int format;
+	public int fps1000;
+    }
+
+    private Camera camera = null;
+    private boolean isRunning = false;
+    private int camIdx;
+    private long userData;
+
+    private Param param = null;
+
+    private SurfaceView surfaceView = null;
+    private SurfaceHolder surfaceHolder = null;
+    private SurfaceTexture surfaceTexture = null;
+
+    public PjCamera(int idx, int w, int h, int fmt, int fps,
+	    	    long userData_, SurfaceView surface)
+    {
+	camIdx = idx;
+	userData = userData_;
+
+	param = new Param();
+	param.width = w;
+	param.height = h;
+	param.format = fmt;
+	param.fps1000 = fps;
+
+	SetSurfaceView(surface);
+    }
+
+    public void SetSurfaceView(SurfaceView surface)
+    {
+	boolean isCaptureRunning = isRunning;
+
+	if (isCaptureRunning)
+	    Stop();
+
+	if (surface != null) {
+	    surfaceView = surface;
+	    surfaceHolder = surfaceView.getHolder();
+	} else {
+	    // Create dummy texture
+	    surfaceHolder = null;
+	    surfaceView = null;
+	    if (surfaceTexture == null) {
+		surfaceTexture = new SurfaceTexture(10);
+	    }
+	}
+
+	if (isCaptureRunning)
+	    Start();
+    }
+
+    public int SwitchDevice(int idx)
+    {
+	boolean isCaptureRunning = isRunning;
+	int oldIdx = camIdx;
+
+	if (isCaptureRunning)
+	    Stop();
+
+	camIdx = idx;
+
+	if (isCaptureRunning) {
+	    int ret = Start();
+	    if (ret != 0) {
+		/* Try to revert back */
+		camIdx = oldIdx;
+		Start();
+		return ret; 
+	    }
+	}
+
+	return 0;
+    }
+
+    public int Start()
+    {
+	try {
+	    camera = Camera.open(camIdx);
+	} catch (Exception e) {
+	    Log.d("IOException", e.getMessage());
+	    return -10;
+	}
+
+	try {
+	    if (surfaceHolder != null) {
+		camera.setPreviewDisplay(surfaceHolder);
+		surfaceHolder.addCallback(this);
+	    } else {
+		camera.setPreviewTexture(surfaceTexture);
+	    }
+	} catch (IOException e) {
+	    Log.d("IOException", e.getMessage());
+	    return -20;
+	}
+
+	Camera.Parameters cp = camera.getParameters();
+	cp.setPreviewSize(param.width, param.height);
+	cp.setPreviewFormat(param.format);
+	// Some devices such as Nexus require an exact FPS range from the
+	// supported FPS ranges, specifying a subset range will raise
+	// exception.
+	//cp.setPreviewFpsRange(param.fps1000, param.fps1000);
+	try {
+	    camera.setParameters(cp);
+	} catch (RuntimeException e) {
+	    Log.d("RuntimeException", e.getMessage());
+	    return -30;
+	}
+
+	camera.setPreviewCallback(this);
+	camera.startPreview();
+	isRunning = true;
+
+	return 0;
+    }
+
+    public void Stop()
+    {
+	isRunning = false;
+	if (camera == null)
+	    return;
+
+	if (surfaceHolder != null)
+	    surfaceHolder.removeCallback(this);
+
+	camera.setPreviewCallback(null);
+	camera.stopPreview();
+	camera.release();
+	camera = null;
+    }
+
+    native void PushFrame(byte[] data, int length, long userData_);
+
+    public void onPreviewFrame(byte[] data, Camera camera)
+    {
+	if (isRunning) {
+	    PushFrame(data, data.length, userData);
+	}
+    }
+
+    public void surfaceChanged(SurfaceHolder holder,
+	int format, int width, int height)
+    {
+	Log.d(TAG, "VideoCaptureAndroid::surfaceChanged");
+    }
+
+    public void surfaceCreated(SurfaceHolder holder)
+    {
+	Log.d(TAG, "VideoCaptureAndroid::surfaceCreated");
+	try {
+	    if(camera != null) {
+		camera.setPreviewDisplay(holder);
+	    }
+	} catch (IOException e) {
+	    Log.e(TAG, "Failed to set preview surface!", e);
+	}
+    }
+
+    public void surfaceDestroyed(SurfaceHolder holder)
+    {
+	Log.d(TAG, "VideoCaptureAndroid::surfaceDestroyed");
+	try {
+	    if(camera != null) {
+		camera.setPreviewDisplay(null);
+	    }
+	} catch (IOException e) {
+	    Log.e(TAG, "Failed to clear preview surface!", e);
+	} catch (RuntimeException e) {
+	    Log.w(TAG, "Clear preview surface useless", e);
+	}
+    }
+
+}
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/PjCameraInfo.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/PjCameraInfo.java	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/PjCameraInfo.java	(revision 5502)
@@ -0,0 +1,110 @@
+/* $Id: PjCameraInfo.java 5019 2015-03-23 06:35:45Z nanang $ */
+/*
+ * Copyright (C) 2015 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;
+
+import java.util.List;
+
+import android.hardware.Camera;
+import android.util.Log;
+
+public class PjCameraInfo {
+    public int facing;
+    public int orient;
+    public int[] supportedSize;		// [w1, h1, w2, h2, ...]
+    public int[] supportedFps1000;	// [min1, max1, min2, max2, ...]
+    public int[] supportedFormat;	// [fmt1, fmt2, ...]
+
+    // convert Format list {fmt1, fmt2, ...} to [fmt1, fmt2, ...]
+    private static int[] IntegerListToIntArray(List<Integer> list)
+    {
+	int[] li = new int[list.size()];
+	int i = 0;
+	for (Integer e : list)  {
+	    li[i++] = e.intValue();
+	}
+	return li;
+    }
+
+    // convert Fps list {[min1, max1], [min2, max2], ...} to 
+    // [min1, max1, min2, max2, ...]
+    private static int[] IntArrayListToIntArray(List<int[]> list)
+    {
+	int[] li = new int[list.size() * 2];
+	int i = 0;
+	for (int[] e : list)  {
+	    li[i++] = e[0];
+	    li[i++] = e[1];
+	}
+	return li;
+    }
+
+    // convert Size list {{w1, h1}, {w2, h2}, ...} to [w1, h1, w2, h2, ...]
+    private static int[] CameraSizeListToIntArray(List<Camera.Size> list)
+    {
+	int[] li = new int[list.size() * 2];
+	int i = 0;
+	for (Camera.Size e : list)  {
+	    li[i++] = e.width;
+	    li[i++] = e.height;
+	}
+	return li;
+    }
+
+    public static int GetCameraCount()
+    {
+	return Camera.getNumberOfCameras();
+    }
+
+    // Get camera info: facing, orientation, supported size/fps/format.
+    // Camera must not be opened.
+    public static PjCameraInfo GetCameraInfo(int idx)
+    {
+	if (idx < 0 || idx >= GetCameraCount())
+	    return null;
+
+	Camera cam;
+	try {
+	    cam = Camera.open(idx);
+	} catch (Exception e) {
+	    Log.d("IOException", e.getMessage());
+	    return null;
+	}
+
+	PjCameraInfo pjci = new PjCameraInfo();
+
+	Camera.CameraInfo ci = new Camera.CameraInfo();
+	Camera.getCameraInfo(idx, ci);
+
+	pjci.facing = ci.facing;
+	pjci.orient = ci.orientation;
+
+	Camera.Parameters param = cam.getParameters();
+	cam.release();
+	cam = null;
+
+	pjci.supportedFormat = IntegerListToIntArray(
+				    param.getSupportedPreviewFormats());
+	pjci.supportedFps1000 = IntArrayListToIntArray(
+				    param.getSupportedPreviewFpsRange());
+	pjci.supportedSize = CameraSizeListToIntArray(
+				    param.getSupportedPreviewSizes());
+
+	return pjci;
+    }
+}
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/CallActivity.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/CallActivity.java	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/CallActivity.java	(revision 5502)
@@ -0,0 +1,364 @@
+/* $Id: CallActivity.java 5138 2015-07-30 06:23:35Z ming $ */
+/*
+ * 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.Display;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+
+import org.pjsip.pjsua2.*;
+
+class VideoPreviewHandler implements SurfaceHolder.Callback
+{   
+    public boolean videoPreviewActive = false;
+        
+    public void updateVideoPreview(SurfaceHolder holder) 
+    {
+	if (MainActivity.currentCall != null &&
+	    MainActivity.currentCall.vidWin != null &&
+	    MainActivity.currentCall.vidPrev != null)
+	{	
+	    if (videoPreviewActive) {
+		VideoWindowHandle vidWH = new VideoWindowHandle();
+		vidWH.getHandle().setWindow(holder.getSurface());
+		VideoPreviewOpParam vidPrevParam = new VideoPreviewOpParam();
+		vidPrevParam.setWindow(vidWH);		
+		try {
+		    MainActivity.currentCall.vidPrev.start(vidPrevParam);
+		} catch (Exception e) {
+		    System.out.println(e);
+		}
+	    } else {
+		try {
+		    MainActivity.currentCall.vidPrev.stop();
+		} catch (Exception e) {
+		    System.out.println(e);
+		}	
+	    }
+	}
+    }    
+    
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
+    {
+	updateVideoPreview(holder);
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) 
+    {
+	
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) 
+    {
+	try {
+	    MainActivity.currentCall.vidPrev.stop();
+	} catch (Exception e) {
+	    System.out.println(e);
+	}
+    }    
+}
+
+public class CallActivity extends Activity
+			  implements Handler.Callback, SurfaceHolder.Callback
+{
+
+    public static Handler handler_;
+    private static VideoPreviewHandler previewHandler = 
+	    					      new VideoPreviewHandler();
+
+    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);
+
+	SurfaceView surfaceInVideo = (SurfaceView)
+				  findViewById(R.id.surfaceIncomingVideo);
+	SurfaceView surfacePreview = (SurfaceView)
+		  		  findViewById(R.id.surfacePreviewCapture);	
+	Button buttonShowPreview = (Button) 
+		  		  findViewById(R.id.buttonShowPreview);	
+	
+	if (MainActivity.currentCall == null ||
+	    MainActivity.currentCall.vidWin == null)
+	{
+	    surfaceInVideo.setVisibility(View.GONE);	    
+	    buttonShowPreview.setVisibility(View.GONE);
+	}
+	setupVideoPreview(surfacePreview, buttonShowPreview);
+	surfaceInVideo.getHolder().addCallback(this);
+	surfacePreview.getHolder().addCallback(previewHandler);
+
+	handler_ = handler;
+	if (MainActivity.currentCall != null) {
+	    try {
+		lastCallInfo = MainActivity.currentCall.getInfo();
+		updateCallState(lastCallInfo);
+	    } catch (Exception e) {
+		System.out.println(e);
+	    }
+	} else {
+	    updateCallState(lastCallInfo);
+	}
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        
+        WindowManager wm;
+        Display display;
+        int rotation;
+        pjmedia_orient orient;
+
+        wm = (WindowManager)this.getSystemService(Context.WINDOW_SERVICE);
+        display = wm.getDefaultDisplay();
+        rotation = display.getRotation();
+        System.out.println("Device orientation changed: " + rotation);
+        
+        switch (rotation) {
+        case Surface.ROTATION_0:   // Portrait
+            orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_270DEG;
+            break;
+        case Surface.ROTATION_90:  // Landscape, home button on the right
+            orient = pjmedia_orient.PJMEDIA_ORIENT_NATURAL;
+            break;
+        case Surface.ROTATION_180:
+            orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_90DEG;
+            break;
+        case Surface.ROTATION_270: // Landscape, home button on the left
+            orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_180DEG;
+            break;
+        default:
+            orient = pjmedia_orient.PJMEDIA_ORIENT_UNKNOWN;
+        }
+
+        if (MyApp.ep != null && MainActivity.account != null) {
+            try {
+        	AccountConfig cfg = MainActivity.account.cfg;
+        	int cap_dev = cfg.getVideoConfig().getDefaultCaptureDevice();
+        	MyApp.ep.vidDevManager().setCaptureOrient(cap_dev, orient,
+        						  true);
+            } catch (Exception e) {
+        	System.out.println(e);
+            }
+        }
+    }    
+
+    @Override
+    protected void onDestroy()
+    {
+	super.onDestroy();
+	handler_ = null;
+    }
+    
+    private void updateVideoWindow(boolean show)
+    { 
+	if (MainActivity.currentCall != null &&
+	    MainActivity.currentCall.vidWin != null &&
+	    MainActivity.currentCall.vidPrev != null)
+	{
+	    SurfaceView surfaceInVideo = (SurfaceView) 
+		       		  findViewById(R.id.surfaceIncomingVideo);
+	    
+	    VideoWindowHandle vidWH = new VideoWindowHandle();	    
+	    if (show) {
+		vidWH.getHandle().setWindow(
+				       surfaceInVideo.getHolder().getSurface());
+	    } else {
+		vidWH.getHandle().setWindow(null);
+	    }
+	    try {
+		MainActivity.currentCall.vidWin.setWindow(vidWH);
+	    } catch (Exception e) {
+		System.out.println(e);
+	    }	    
+	}
+    }
+     
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
+    {
+	updateVideoWindow(true);
+    }
+
+    public void surfaceCreated(SurfaceHolder holder)
+    {
+    }
+
+    public void surfaceDestroyed(SurfaceHolder holder)
+    {
+	updateVideoWindow(false);
+    }
+
+    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);
+	    }
+	}
+    }
+    
+    public void setupVideoPreview(SurfaceView surfacePreview, 
+	    			  Button buttonShowPreview)
+    {
+	surfacePreview.setVisibility(previewHandler.videoPreviewActive?
+		     		     View.VISIBLE:View.GONE);
+	
+	buttonShowPreview.setText(previewHandler.videoPreviewActive?
+		  		  getString(R.string.hide_preview):
+		  		  getString(R.string.show_preview));		
+    }
+    
+    public void showPreview(View view)
+    {
+	SurfaceView surfacePreview = (SurfaceView)
+		  	          findViewById(R.id.surfacePreviewCapture);	
+
+	Button buttonShowPreview = (Button) 
+		  		  findViewById(R.id.buttonShowPreview);
+	
+	
+	previewHandler.videoPreviewActive = !previewHandler.videoPreviewActive;
+	
+	setupVideoPreview(surfacePreview, buttonShowPreview);
+	
+	previewHandler.updateVideoPreview(surfacePreview.getHolder());
+    }
+
+    private void setupVideoSurface()
+    {
+	SurfaceView surfaceInVideo = (SurfaceView)
+				  findViewById(R.id.surfaceIncomingVideo);
+	SurfaceView surfacePreview = (SurfaceView)
+		  		  findViewById(R.id.surfacePreviewCapture);
+	Button buttonShowPreview = (Button)
+		  		  findViewById(R.id.buttonShowPreview);	
+	surfaceInVideo.setVisibility(View.VISIBLE);
+	buttonShowPreview.setVisibility(View.VISIBLE);
+	surfacePreview.setVisibility(View.GONE);	
+    }
+
+    @Override
+    public boolean handleMessage(Message m)
+    {
+	if (m.what == MainActivity.MSG_TYPE.CALL_STATE) {
+
+	    lastCallInfo = (CallInfo) m.obj;
+	    updateCallState(lastCallInfo);
+
+	} else if (m.what == MainActivity.MSG_TYPE.CALL_MEDIA_STATE) {
+
+	    if (MainActivity.currentCall.vidWin != null) {
+		/* Set capture orientation according to current
+		 * device orientation.
+		 */
+		onConfigurationChanged(getResources().getConfiguration());
+		/* If there's incoming video, display it. */
+		setupVideoSurface();
+	    }
+
+	} 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();
+	    }
+	}
+
+	tvPeer.setText(ci.getRemoteUri());
+	tvState.setText(call_state);
+    }
+}
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java	(revision 5502)
@@ -0,0 +1,581 @@
+/* $Id: MainActivity.java 5022 2015-03-25 03:41:21Z nanang $ */
+/*
+ * 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;
+	public final static int CALL_MEDIA_STATE = 5;
+    }
+
+    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, for native debugging only
+	    if (false &&
+		(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");
+	    accCfg.getNatConfig().setIceEnabled(true);
+	    accCfg.getVideoConfig().setAutoTransmitOutgoing(true);
+	    accCfg.getVideoConfig().setAutoShowIncoming(true);
+	    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();
+	    }
+
+	} else if (m.what == MSG_TYPE.CALL_MEDIA_STATE) {
+
+	    /* Forward the message to CallActivity */
+	    if (CallActivity.handler_ != null) {
+		Message m2 = Message.obtain(CallActivity.handler_,
+		    MSG_TYPE.CALL_MEDIA_STATE,
+		    null);
+		m2.sendToTarget();
+	    }
+
+	} else if (m.what == MSG_TYPE.BUDDY_STATE) {
+
+	    MyBuddy buddy = (MyBuddy) m.obj;
+	    int idx = account.buddyList.indexOf(buddy);
+
+	    /* Update buddy status text, if buddy is valid and
+	    * the buddy lists in account and UI are sync-ed.
+	    */
+	    if (idx >= 0 && account.buddyList.size() == buddyList.size())
+	    {
+		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) {}
+		*/
+		// TODO: set status code
+		call.delete();
+		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.length()!=0) {
+	    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.length() != 0) {
+			creds.add(new AuthCredInfo("Digest", "*", username, 0,
+						   password));
+		    }
+		    StringVector proxies = accCfg.getSipConfig().getProxies();
+		    proxies.clear();
+		    if (proxy.length() != 0) {
+			proxies.add(proxy);
+		    }
+
+		    /* Enable ICE */
+		    accCfg.getNatConfig().setIceEnabled(true);
+
+		    /* 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(true);
+
+	try {
+	    call.makeCall(buddy_uri, prm);
+	} catch (Exception e) {
+	    call.delete();
+	    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();
+
+	if (ci != null &&
+	    ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
+	{
+	    currentCall = null;
+	}
+    }
+
+    public void notifyCallMediaState(MyCall call)
+    {
+	Message m = Message.obtain(handler, MSG_TYPE.CALL_MEDIA_STATE, null);
+	m.sendToTarget();
+    }
+
+    public void notifyBuddyState(MyBuddy buddy)
+    {
+	Message m = Message.obtain(handler, MSG_TYPE.BUDDY_STATE, buddy);
+	m.sendToTarget();
+    }
+
+    /* === end of MyAppObserver ==== */
+
+}
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java	(revision 5502)
@@ -0,0 +1,540 @@
+/* $Id: MyApp.java 5361 2016-06-28 14:32:08Z nanang $ */
+/*
+ * 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 notifyCallMediaState(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
+{
+    public VideoWindow vidWin;
+    public VideoPreview vidPrev;
+
+    MyCall(MyAccount acc, int call_id)
+    {
+	super(acc, call_id);
+	vidWin = null;
+    }
+
+    @Override
+    public void onCallState(OnCallStateParam prm)
+    {
+	    MyApp.observer.notifyCallState(this);
+	    try {
+		CallInfo ci = getInfo();
+		if (ci.getState() == 
+		    pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
+		{
+		    this.delete();
+		}
+	    } catch (Exception e) {
+		return;
+	    }
+    }
+
+    @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;
+		}
+	    } else if (cmi.getType() == pjmedia_type.PJMEDIA_TYPE_VIDEO &&
+		       cmi.getStatus() == 
+			    pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE &&
+		       cmi.getVideoIncomingWindowId() != pjsua2.INVALID_ID)
+	    {
+		vidWin = new VideoWindow(cmi.getVideoIncomingWindowId());
+		vidPrev = new VideoPreview(cmi.getVideoCapDev());
+	    }
+	}
+
+	MyApp.observer.notifyCallMediaState(this);
+    }
+}
+
+
+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.delete();
+	    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);
+	buddy.delete();
+    }
+
+    public void delBuddy(int index)
+    {
+	MyBuddy bud = buddyList.get(index);
+	buddyList.remove(index);
+	bud.delete();
+    }
+
+    @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.length()==0) {
+		    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 {
+	try{
+	    System.loadLibrary("openh264");
+            // Ticket #1937: libyuv is now included as static lib
+            //System.loadLibrary("yuv");
+	} catch (UnsatisfiedLinkError e) {
+	    System.out.println("UnsatisfiedLinkError: " + e.getMessage());
+	    System.out.println("This could be safely ignored if you " +
+			       "don't need video.");
+	}
+	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("Pjsua2 Android " + ep.libVersion().getFull());
+	StringVector stun_servers = new StringVector();
+	stun_servers.add("stun.pjsip.org");
+	ua_cfg.setStunServer(stun_servers);
+	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);
+
+	    /* Customize account config */
+	    my_cfg.accCfg.getNatConfig().setIceEnabled(true);
+	    my_cfg.accCfg.getVideoConfig().setAutoTransmitOutgoing(true);
+	    my_cfg.accCfg.getVideoConfig().setAutoShowIncoming(true);
+
+	    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;
+    } 
+}
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/drawable/bkg.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/drawable/bkg.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/drawable/bkg.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/activity_call.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/activity_call.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/activity_call.xml	(revision 5502)
@@ -0,0 +1,73 @@
+<?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" />
+    
+	<LinearLayout 
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">    
+        
+        <LinearLayout 
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_weight=".50">    
+	    	    
+            <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" />
+		    
+            <Button
+                android:id="@+id/buttonShowPreview"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"		        
+                android:onClick="showPreview"
+                android:text="@+string/show_preview" />
+	    
+        </LinearLayout>
+        <SurfaceView
+            android:id="@+id/surfacePreviewCapture"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight=".50" />			    
+	    
+    </LinearLayout>
+   
+    <SurfaceView
+       	android:id="@+id/surfaceIncomingVideo"
+       	android:layout_width="match_parent"
+       	android:layout_height="match_parent" />
+	
+</LinearLayout>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/activity_main.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/activity_main.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/activity_main.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/dlg_account_config.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/dlg_account_config.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/dlg_account_config.xml	(revision 5502)
@@ -0,0 +1,78 @@
+<?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|textEmailAddress" >
+
+	        <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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/dlg_add_buddy.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/dlg_add_buddy.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/layout/dlg_add_buddy.xml	(revision 5502)
@@ -0,0 +1,26 @@
+<?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|textEmailAddress" >
+
+	        <requestFocus />
+	    </EditText>
+    </TableRow>
+	<TableRow>
+        <CheckBox
+            android:id="@+id/checkBoxSubscribe"
+            android:layout_column="1"
+            android:text="Subscribe presence" />
+    </TableRow>
+</TableLayout>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/menu/call.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/menu/call.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/menu/call.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/menu/main.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/menu/main.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/menu/main.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-sw600dp/dimens.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-sw600dp/dimens.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-sw600dp/dimens.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-sw720dp-land/dimens.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-sw720dp-land/dimens.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-sw720dp-land/dimens.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-v11/styles.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-v11/styles.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-v11/styles.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-v14/styles.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-v14/styles.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values-v14/styles.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/colors.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/colors.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/colors.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/dimens.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/dimens.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/dimens.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/strings.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/strings.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/strings.xml	(revision 5502)
@@ -0,0 +1,10 @@
+<?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>
+    <string name="show_preview">Show Preview</string>
+    <string name="hide_preview">Hide Preview</string>
+</resources>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/styles.xml
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/styles.xml	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/res/values/styles.xml	(revision 5502)
@@ -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>
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/build.gradle
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/build.gradle	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/build.gradle	(revision 5502)
@@ -0,0 +1,15 @@
+// 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:2.2.3'
+    }
+}
+
+allprojects {
+    repositories {
+        jcenter()
+    }
+}
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/gradle/wrapper/gradle-wrapper.properties
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/gradle/wrapper/gradle-wrapper.properties	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/gradle/wrapper/gradle-wrapper.properties	(revision 5502)
@@ -0,0 +1,6 @@
+#Mon Dec 28 10:00:20 PST 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/gradlew
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/gradlew	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/gradlew	(revision 5502)
@@ -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 "$@"
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/gradlew.bat
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/gradlew.bat	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/gradlew.bat	(revision 5502)
@@ -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
Index: project/trunk/pjsip-apps/src/swig/java/android/proguard-project.txt
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/proguard-project.txt	(revision 5501)
+++ 	(revision )
@@ -1,20 +1,0 @@
-# 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 *;
-#}
Index: project/trunk/pjsip-apps/src/swig/java/android/project.properties
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/project.properties	(revision 5501)
+++ 	(revision )
@@ -1,14 +1,0 @@
-# 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
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/settings.gradle
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/settings.gradle	(revision 5502)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/settings.gradle	(revision 5502)
@@ -0,0 +1,1 @@
+include ':app'
