Index: pjproject/branches/projects/android/pjsip-apps/src/apjloader/AndroidManifest.xml
===================================================================
--- pjproject/branches/projects/android/pjsip-apps/src/apjloader/AndroidManifest.xml	(revision 4289)
+++ pjproject/branches/projects/android/pjsip-apps/src/apjloader/AndroidManifest.xml	(revision 4292)
@@ -7,5 +7,5 @@
         android:minSdkVersion="15"
         android:targetSdkVersion="15" />
-    
+
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
@@ -16,22 +16,15 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
-    <uses-permission android:name="android.permission.READ_CONTACTS" />
-    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
-    <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.VIBRATE" />
-    <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.READ_LOGS" />
     <uses-permission android:name="android.permission.USE_SIP" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.CAMERA" />
-    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
-    <uses-permission android:name="android.permission.READ_PROFILE" />
- 
-    <uses-feature android:name="android.hardware.sip.voip" android:required="true" />
-    <uses-feature android:name="android.hardware.microphone" android:required="true" />
-    
+
+    <uses-feature
+        android:name="android.hardware.microphone"
+        android:required="true" />
+
     <application
         android:icon="@drawable/ic_launcher"
@@ -39,7 +32,6 @@
         android:theme="@android:style/Theme.DeviceDefault.NoActionBar" >
         <activity
-            android:screenOrientation="portrait"
-            android:configChanges="keyboardHidden|orientation|screenLayout"
             android:name=".MainActivity"
+            android:windowSoftInputMode="stateHidden"
             android:label="@string/title_activity_main" >
             <intent-filter>
Index: pjproject/branches/projects/android/pjsip-apps/src/apjloader/src/org/pjsip/apjloader/MainActivity.java
===================================================================
--- pjproject/branches/projects/android/pjsip-apps/src/apjloader/src/org/pjsip/apjloader/MainActivity.java	(revision 4289)
+++ pjproject/branches/projects/android/pjsip-apps/src/apjloader/src/org/pjsip/apjloader/MainActivity.java	(revision 4292)
@@ -2,4 +2,6 @@
 
 package org.pjsip.apjloader;
+
+import java.lang.ref.WeakReference;
 
 import android.app.Activity;
@@ -10,4 +12,5 @@
 import android.os.Message;
 import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
@@ -22,5 +25,6 @@
 	public static final String TAG = "apjloader";
 	public static final String NEWLINE = "\r\n";
-	public static final Boolean AUTOKILL_ON_FINISHED = true;
+	public static final Boolean AUTOKILL_ON_FINISH = false;
+	public static final int MAX_LOG_CHARS = 20000; // set to zero to disable limit
 	public enum MSG_TYPE {
 		STR_INFO,
@@ -42,8 +46,12 @@
 
 class LoaderThread extends Thread {
-	private Handler ui_handler;
+	private WeakReference<Handler> ui_handler;
 
 	public LoaderThread(Handler ui_handler_) {
-		ui_handler = ui_handler_;
+		set_ui_handler(ui_handler_);
+	}
+	
+	public void set_ui_handler(Handler ui_handler_) {
+		ui_handler = new WeakReference<Handler>(ui_handler_);
 	}
 	
@@ -56,16 +64,20 @@
 						 "--clock-rate=8000",
 						 "--auto-answer=200",
-						};
-		
-		LOG.INFO(ui_handler, "Starting module.." + CONST.NEWLINE);
+						 };
+		
+		Handler ui = ui_handler.get();
+		LOG.INFO(ui, "Starting module.." + CONST.NEWLINE);
 		int rc = apjloader.main(argv.length, argv);
-		LOG.INFO(ui_handler, "Module finished with return code: " + 
+		
+		ui = ui_handler.get();
+		LOG.INFO(ui, "Module finished with return code: " + 
 				 Integer.toString(rc) + CONST.NEWLINE);
 		
 		apjloader.destroy_stdio_pipe();
 
-		if (CONST.AUTOKILL_ON_FINISHED) {
-			Message msg = Message.obtain(ui_handler, CONST.MSG_TYPE.QUIT.ordinal());
-			ui_handler.sendMessageDelayed(msg, 2000);
+		if (CONST.AUTOKILL_ON_FINISH) {
+			ui = ui_handler.get();
+			Message msg = Message.obtain(ui, CONST.MSG_TYPE.QUIT.ordinal());
+			ui.sendMessageDelayed(msg, 2000);
 		}
 	}
@@ -73,8 +85,12 @@
 
 class OutputThread extends Thread {
-	private Handler ui_handler;
+	private WeakReference<Handler> ui_handler;
 	
 	public OutputThread(Handler ui_handler_) {
-		ui_handler  = ui_handler_;
+		set_ui_handler(ui_handler_);
+	}
+	
+	public void set_ui_handler(Handler ui_handler_) {
+		ui_handler = new WeakReference<Handler>(ui_handler_);
 	}
 	
@@ -87,9 +103,10 @@
 			byte ch[] = new byte[1];
 			int rc = apjloader.read_from_stdout(ch);
+			Handler ui = ui_handler.get();
 			
 			if (rc == 0) {
 				if (ch[0]=='\r' || ch[0]== '\n') {
 					if (sb.length() > 0) {
-						LOG.INFO(ui_handler, sb.toString()+CONST.NEWLINE);
+						LOG.INFO(ui, sb.toString()+CONST.NEWLINE);
 						sb.delete(0, sb.length());
 					}
@@ -98,5 +115,5 @@
 				}					
 			} else {
-				LOG.INFO(ui_handler, "Stdout pipe stopped, rc="+Integer.toString(rc)+CONST.NEWLINE);
+				LOG.INFO(ui, "Stdout pipe stopped, rc="+Integer.toString(rc)+CONST.NEWLINE);
 				break;
 			}
@@ -109,20 +126,107 @@
 	private TextView log_view;
 	private ScrollView log_scroll_view;
-	EditText input_cmd;
-
-	/** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    	setContentView(R.layout.activity_main);
-
-        init_view();
-        
-        print_log("Loading module.." + CONST.NEWLINE);
-        int rc = init_lib();
-        if (rc != 0)
+	private EditText input_cmd;
+	private MyHandler ui_handler = new MyHandler(this);
+	private static OutputThread ot;
+	private static LoaderThread lt;
+	
+	private static class MyHandler extends Handler {
+		private final WeakReference<MainActivity> mTarget;
+		
+		public MyHandler(MainActivity target) {
+			mTarget = new WeakReference<MainActivity>(target); 
+		}
+		
+		@Override
+		public void handleMessage(Message m) {
+			MainActivity target = mTarget.get();
+			if (target == null)
+				return;
+			
+			if (m.what == CONST.MSG_TYPE.STR_INFO.ordinal() ||
+				m.what == CONST.MSG_TYPE.STR_ERROR.ordinal())
+			{
+				target.print_log((String)m.obj);
+			} else if (m.what == CONST.MSG_TYPE.QUIT.ordinal()) {
+				target.finish();
+				System.gc();
+				android.os.Process.killProcess(android.os.Process.myPid());
+			}
+		}
+    }
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+    	Log.d(CONST.TAG, "=== Activity::onCreate() ===");
+    	super.onCreate(savedInstanceState);
+    	
+    	init_view();
+
+    	int rc = init_lib();
+        if (rc != 0) {
         	print_log("Failed loading module: " + Integer.toString(rc) + CONST.NEWLINE);
-	}
-
+        	return;
+        }
+
+        ot.set_ui_handler(ui_handler);
+        lt.set_ui_handler(ui_handler);
+	}
+
+    @Override
+    protected void onStart() {
+    	Log.d(CONST.TAG, "=== Activity::onStart() ===");
+    	super.onStart();
+    }
+    
+    @Override
+    protected void onRestart() {
+    	Log.d(CONST.TAG, "=== Activity::onRestart() ===");
+    	super.onRestart();
+    }
+
+    @Override
+    protected void onResume() {
+    	Log.d(CONST.TAG, "=== Activity::onResume() ===");
+    	super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+    	Log.d(CONST.TAG, "=== Activity::onPause() ===");
+    	super.onPause();
+    }
+
+    @Override
+    protected void onStop() {
+    	Log.d(CONST.TAG, "=== Activity::onStop() ===");
+    	super.onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+    	Log.d(CONST.TAG, "=== Activity::onDestroy() ===");
+    	super.onDestroy();
+    }
+    
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+		super.onSaveInstanceState(outState);
+		outState.putString("INPUT_CMD", input_cmd.getText().toString());
+		outState.putString("LOG_VIEW", log_view.getText().toString());
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+		super.onRestoreInstanceState(savedInstanceState);
+		input_cmd.setText(savedInstanceState.getString("INPUT_CMD"));
+		log_view.setText(savedInstanceState.getString("LOG_VIEW"));
+    	log_view.post(new Runnable() {
+            public void run() {
+            	log_scroll_view.fullScroll(View.FOCUS_DOWN);
+            }
+        });   	
+    }
+    
+          
     private View.OnClickListener on_send_cmd_click = new View.OnClickListener() {
     	public void onClick(View v) {
@@ -161,6 +265,15 @@
     private void print_log(String st) {
     	log_view.append(st);
-    	//Log.i(CONST.TAG, st);
-
+    	Log.d(CONST.TAG, st);
+    	
+    	// Limit log view text length
+    	if (CONST.MAX_LOG_CHARS > 0 && log_view.length() > CONST.MAX_LOG_CHARS) {
+    		int to_del = log_view.length() - CONST.MAX_LOG_CHARS + 100;
+    		if (to_del > log_view.length())
+    			to_del = log_view.length();
+        	log_view.getEditableText().delete(0, to_del);
+    	}
+
+    	// Scroll to bottom
     	log_view.post(new Runnable() {
             public void run() {
@@ -170,19 +283,4 @@
     }
     
-    private Handler ui_handler = new Handler() {
-		@Override
-		public void handleMessage(Message m) {
-			if (m.what == CONST.MSG_TYPE.STR_INFO.ordinal() ||
-				m.what == CONST.MSG_TYPE.STR_ERROR.ordinal())
-			{
-				print_log((String)m.obj);
-			} else if (m.what == CONST.MSG_TYPE.QUIT.ordinal()) {
-				finish();
-				System.gc();
-				android.os.Process.killProcess(android.os.Process.myPid());
-			}
-		}
-    };
-
     private void hide_soft_keyboard() {
         InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -191,5 +289,7 @@
     
 	private void init_view() {
-        Button send_cmd_button = (Button)findViewById(R.id.send_cmd_button);
+    	setContentView(R.layout.activity_main);
+
+    	Button send_cmd_button = (Button)findViewById(R.id.send_cmd_button);
         send_cmd_button.setOnClickListener(on_send_cmd_click);
 
@@ -199,21 +299,17 @@
         input_cmd = (EditText)findViewById(R.id.input_cmd);
         input_cmd.setOnKeyListener(on_input_cmd_key);
-        
+
         log_view = (TextView)findViewById(R.id.output);
         log_view.setMovementMethod(new ScrollingMovementMethod());
-        log_view.setText("");
         
         log_scroll_view = (ScrollView)findViewById(R.id.output_scroller);
 	}
 	
-	private int init_stdio_pipes() {
-		int rc = apjloader.init_stdio_pipe();
-		if (rc != 0)
-			return rc;
-		
-		return 0;
-	}
-	
 	private int init_lib() {
+		if (ot != null || lt != null)
+			return 0;
+		
+        print_log("Loading module.." + CONST.NEWLINE);
+        
 		try {
 			System.loadLibrary(CONST.LIB_FILENAME);
@@ -232,11 +328,11 @@
 		}
 		
-        int rc = init_stdio_pipes();
+		int rc = apjloader.init_stdio_pipe();
         print_log("Stdio pipes inited: " + Integer.toString(rc) + CONST.NEWLINE);
         
-    	OutputThread ot = new OutputThread(ui_handler);
+    	ot = new OutputThread(ui_handler);
 		ot.start();
 		
-        LoaderThread lt = new LoaderThread(ui_handler);
+        lt = new LoaderThread(ui_handler);
         lt.start();
         
