From e01ef25ab97d22174e129153ea1d867464b7c728 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Thu, 1 Nov 2012 06:14:15 +0000 Subject: [PATCH] Re #1546: apjloader updates: handle activity destroy-recreate, e.g: on orientation change or device sleep, and minors (cleaner activity handler, copy log to logcat, etc). git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/android@4292 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip-apps/src/apjloader/AndroidManifest.xml | 22 +- .../src/org/pjsip/apjloader/MainActivity.java | 204 +++++++++++++----- 2 files changed, 157 insertions(+), 69 deletions(-) diff --git a/pjsip-apps/src/apjloader/AndroidManifest.xml b/pjsip-apps/src/apjloader/AndroidManifest.xml index bd6023570..adc3cb248 100644 --- a/pjsip-apps/src/apjloader/AndroidManifest.xml +++ b/pjsip-apps/src/apjloader/AndroidManifest.xml @@ -6,7 +6,7 @@ - + @@ -15,32 +15,24 @@ - - - - - - - - - - - - + + + diff --git a/pjsip-apps/src/apjloader/src/org/pjsip/apjloader/MainActivity.java b/pjsip-apps/src/apjloader/src/org/pjsip/apjloader/MainActivity.java index 98f617b6f..4523e29fd 100644 --- a/pjsip-apps/src/apjloader/src/org/pjsip/apjloader/MainActivity.java +++ b/pjsip-apps/src/apjloader/src/org/pjsip/apjloader/MainActivity.java @@ -2,6 +2,8 @@ package org.pjsip.apjloader; +import java.lang.ref.WeakReference; + import android.app.Activity; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -9,6 +11,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.method.ScrollingMovementMethod; +import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -21,7 +24,8 @@ class CONST { public static final String LIB_FILENAME = "apjloader"; 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, STR_ERROR, @@ -41,10 +45,14 @@ class LOG { } class LoaderThread extends Thread { - private Handler ui_handler; + private WeakReference 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(ui_handler_); } public void run() { @@ -55,27 +63,35 @@ class LoaderThread extends Thread { String argv[] = {"", "--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); } } } class OutputThread extends Thread { - private Handler ui_handler; + private WeakReference 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(ui_handler_); } public void run() { @@ -86,18 +102,19 @@ class OutputThread extends Thread { { 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()); } } else { sb.append((char)ch[0]); } } 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; } } @@ -108,22 +125,109 @@ class OutputThread extends Thread { public class MainActivity extends Activity { private TextView log_view; private ScrollView log_scroll_view; - EditText input_cmd; - - /** Called when the activity is first created. */ + 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 mTarget; + + public MyHandler(MainActivity target) { + mTarget = new WeakReference(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 - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); + protected void onCreate(Bundle savedInstanceState) { + Log.d(CONST.TAG, "=== Activity::onCreate() ==="); + super.onCreate(savedInstanceState); + + init_view(); - init_view(); - - print_log("Loading module.." + CONST.NEWLINE); - int rc = init_lib(); - if (rc != 0) + 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) { String cmd = input_cmd.getText().toString().trim(); @@ -160,8 +264,17 @@ public class MainActivity extends Activity { 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() { log_scroll_view.fullScroll(View.FOCUS_DOWN); @@ -169,28 +282,15 @@ public class MainActivity extends Activity { }); } - 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); imm.hideSoftInputFromWindow(input_cmd.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } 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); Button quit_button = (Button)findViewById(R.id.quit_button); @@ -198,23 +298,19 @@ public class MainActivity extends Activity { 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); } catch (UnsatisfiedLinkError e) { @@ -231,13 +327,13 @@ public class MainActivity extends Activity { } } - 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(); return 0;