From cadb6e8c1e1f09afef2a0c3bc4edf443ccf0d2e8 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Fri, 24 Jun 2011 03:23:19 +0000
Subject: [PATCH] - Set android log tag to "I2P" - Log to console buffer too -
 New log activity - Debug status output when router not running - More logging
 utility methods

---
 AndroidManifest.xml                           |  4 +
 res/layout/logs_header.xml                    |  8 ++
 res/layout/logs_list_item.xml                 |  7 ++
 res/layout/main.xml                           | 12 +++
 res/raw/logger_config                         |  1 +
 .../android/router/activity/LogActivity.java  | 70 +++++++++++++++++
 .../android/router/activity/MainActivity.java | 75 +++++++++++++------
 .../android/router/service/RouterService.java |  7 +-
 src/net/i2p/android/router/util/Util.java     | 63 ++++++++++++++++
 src/net/i2p/util/LogWriter.java               | 34 ++++++---
 10 files changed, 248 insertions(+), 33 deletions(-)
 create mode 100644 res/layout/logs_header.xml
 create mode 100644 res/layout/logs_list_item.xml
 create mode 100644 src/net/i2p/android/router/activity/LogActivity.java

diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6481eee1c..45d816fe9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -50,5 +50,9 @@
                   android:label="Address Book"
                   android.theme="@android:style/Theme.NoTitleBar" >
         </activity>
+        <activity android:name=".activity.LogActivity"
+                  android:label="Logs"
+                  android.theme="@android:style/Theme.NoTitleBar" >
+        </activity>
     </application>
 </manifest> 
diff --git a/res/layout/logs_header.xml b/res/layout/logs_header.xml
new file mode 100644
index 000000000..b3a12859b
--- /dev/null
+++ b/res/layout/logs_header.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content" 
+    android:padding="8dp"
+    android:textSize="18sp"
+    android:text="Logs" >
+</TextView>
diff --git a/res/layout/logs_list_item.xml b/res/layout/logs_list_item.xml
new file mode 100644
index 000000000..7e058a0f9
--- /dev/null
+++ b/res/layout/logs_list_item.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:padding="6dp"
+    android:textSize="16sp" >
+</TextView>
diff --git a/res/layout/main.xml b/res/layout/main.xml
index fd46fb27d..5620f4e19 100644
--- a/res/layout/main.xml
+++ b/res/layout/main.xml
@@ -69,6 +69,18 @@
     android:layout_height="wrap_content" 
     android:text="Address Book"
     />
+ <Button 
+    android:id="@+id/logs_button"
+    android:layout_width="wrap_content" 
+    android:layout_height="wrap_content" 
+    android:text="Logs"
+    />
+ <Button 
+    android:id="@+id/error_button"
+    android:layout_width="wrap_content" 
+    android:layout_height="wrap_content" 
+    android:text="Error Logs"
+    />
 </LinearLayout>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
diff --git a/res/raw/logger_config b/res/raw/logger_config
index f73f9459b..b83d079e0 100644
--- a/res/raw/logger_config
+++ b/res/raw/logger_config
@@ -1,3 +1,4 @@
+logger.consoleBufferSize=250
 logger.dateFormat=MM/dd HH:mm:ss.SSS
 logger.defaultLevel=INFO
 logger.displayOnScreen=true
diff --git a/src/net/i2p/android/router/activity/LogActivity.java b/src/net/i2p/android/router/activity/LogActivity.java
new file mode 100644
index 000000000..a4ba44e85
--- /dev/null
+++ b/src/net/i2p/android/router/activity/LogActivity.java
@@ -0,0 +1,70 @@
+package net.i2p.android.router.activity;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.i2p.I2PAppContext;
+import net.i2p.android.router.R;
+
+public class LogActivity extends ListActivity {
+
+    boolean errorsOnly;
+
+    final static String ERRORS_ONLY = "errors_only";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+
+        // Grab context if router has started, otherwise create new
+        // FIXME dup contexts, locking, ...
+        List<String> msgs;
+        String header;
+        I2PAppContext ctx = I2PAppContext.getCurrentContext();
+        if (ctx != null) {
+            Intent intent = getIntent();
+            errorsOnly = intent.getBooleanExtra(ERRORS_ONLY, false);
+            if (errorsOnly) {
+                msgs = ctx.logManager().getBuffer().getMostRecentCriticalMessages();
+            } else {
+                msgs = ctx.logManager().getBuffer().getMostRecentMessages();
+            }
+            int sz = msgs.size();
+            if (sz == 0) {
+                header = "No messages";
+            } else if (sz == 1) {
+                header = "1 message";
+            } else {
+                header = sz + " messages, newest first";
+                Collections.reverse(msgs);
+            }
+        } else {
+            msgs = Collections.EMPTY_LIST;
+            header = "No messages";
+        }
+
+        // set the header
+        TextView tv = (TextView) getLayoutInflater().inflate(R.layout.logs_header, null);
+        tv.setText(header);
+        ListView lv = getListView();
+        lv.addHeaderView(tv, "", false);
+        setListAdapter(new ArrayAdapter<String>(this, R.layout.logs_list_item, msgs));
+
+        // set the callback
+        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            public void onItemClick(AdapterView parent, View view, int pos, long id) {
+                // make it bigger or something
+            }
+        });
+    }
+}
diff --git a/src/net/i2p/android/router/activity/MainActivity.java b/src/net/i2p/android/router/activity/MainActivity.java
index 23934f087..4220a301f 100644
--- a/src/net/i2p/android/router/activity/MainActivity.java
+++ b/src/net/i2p/android/router/activity/MainActivity.java
@@ -38,16 +38,16 @@ public class MainActivity extends I2PActivityBase {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
 
-        Button news = (Button) findViewById(R.id.news_button);
-        news.setOnClickListener(new View.OnClickListener() {
+        Button b = (Button) findViewById(R.id.news_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 Intent intent = new Intent(view.getContext(), NewsActivity.class);
                 startActivity(intent);
             }
         });
 
-        Button notes = (Button) findViewById(R.id.releasenotes_button);
-        notes.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.releasenotes_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 Intent intent = new Intent(view.getContext(), TextResourceActivity.class);
                 intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt);
@@ -55,8 +55,8 @@ public class MainActivity extends I2PActivityBase {
             }
         });
 
-        Button licenses = (Button) findViewById(R.id.licenses_button);
-        licenses.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.licenses_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 Intent intent = new Intent(view.getContext(), LicenseActivity.class);
                 //Intent intent = new Intent(view.getContext(), TextResourceActivity.class);
@@ -65,8 +65,8 @@ public class MainActivity extends I2PActivityBase {
             }
         });
 
-        Button website = (Button) findViewById(R.id.website_button);
-        website.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.website_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 Intent intent = new Intent(view.getContext(), WebActivity.class);
                 //intent.setData((new Uri.Builder()).scheme("http").authority("www.i2p2.de").path("/").build());
@@ -75,8 +75,8 @@ public class MainActivity extends I2PActivityBase {
             }
         });
 
-        Button faq = (Button) findViewById(R.id.faq_button);
-        faq.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.faq_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 Intent intent = new Intent(view.getContext(), WebActivity.class);
                 //intent.setData((new Uri.Builder()).scheme("http").authority("www.i2p2.de").path("/faq").build());
@@ -85,8 +85,8 @@ public class MainActivity extends I2PActivityBase {
             }
         });
 
-        Button welcome = (Button) findViewById(R.id.welcome_button);
-        welcome.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.welcome_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 Intent intent = new Intent(view.getContext(), WebActivity.class);
                 // default is to display the welcome_html resource
@@ -94,16 +94,33 @@ public class MainActivity extends I2PActivityBase {
             }
         });
 
-        Button addressbook = (Button) findViewById(R.id.addressbook_button);
-        addressbook.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.addressbook_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 Intent intent = new Intent(view.getContext(), AddressbookActivity.class);
                 startActivity(intent);
             }
         });
 
-        Button start = (Button) findViewById(R.id.router_start_button);
-        start.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.logs_button);
+        b.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View view) {
+                Intent intent = new Intent(view.getContext(), LogActivity.class);
+                startActivity(intent);
+            }
+        });
+
+        b = (Button) findViewById(R.id.error_button);
+        b.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View view) {
+                Intent intent = new Intent(view.getContext(), LogActivity.class);
+                intent.putExtra(LogActivity.ERRORS_ONLY, true);
+                startActivity(intent);
+            }
+        });
+
+        b = (Button) findViewById(R.id.router_start_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 RouterService svc = _routerService;
                 if (svc != null && _isBound) {
@@ -116,8 +133,8 @@ public class MainActivity extends I2PActivityBase {
             }
         });
 
-        Button stop = (Button) findViewById(R.id.router_stop_button);
-        stop.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.router_stop_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 RouterService svc = _routerService;
                 if (svc != null && _isBound) {
@@ -128,8 +145,8 @@ public class MainActivity extends I2PActivityBase {
             }
         });
 
-        Button quit = (Button) findViewById(R.id.router_quit_button);
-        quit.setOnClickListener(new View.OnClickListener() {
+        b = (Button) findViewById(R.id.router_quit_button);
+        b.setOnClickListener(new View.OnClickListener() {
             public void onClick(View view) {
                 RouterService svc = _routerService;
                 if (svc != null && _isBound) {
@@ -157,6 +174,7 @@ public class MainActivity extends I2PActivityBase {
     {
         super.onStart();
         _handler.removeCallbacks(_updater);
+        _handler.removeCallbacks(_oneShotUpdate);
         if (_savedStatus != null) {
             TextView tv = (TextView) findViewById(R.id.main_status_text);
             tv.setText(_savedStatus);
@@ -170,6 +188,7 @@ public class MainActivity extends I2PActivityBase {
     {
         super.onStop();
         _handler.removeCallbacks(_updater);
+        _handler.removeCallbacks(_oneShotUpdate);
     }
 
     @Override
@@ -227,10 +246,11 @@ public class MainActivity extends I2PActivityBase {
     private void updateStatus() {
         RouterContext ctx = getRouterContext();
         TextView tv = (TextView) findViewById(R.id.main_status_text);
+/***
         if (!Util.isConnected(this)) {
             tv.setText("No Internet connection is available");
             tv.setVisibility(View.VISIBLE);
-        } else if (ctx != null) {
+        } else ****/ if (ctx != null) {
             int active = ctx.commSystem().countActivePeers();
             int known = Math.max(ctx.netDb().getKnownRouters() - 1, 0);
             int inEx = ctx.tunnelManager().getFreeTunnelCount();
@@ -273,7 +293,18 @@ public class MainActivity extends I2PActivityBase {
             tv.setText(_savedStatus);
             tv.setVisibility(View.VISIBLE);
         } else {
-            tv.setVisibility(View.INVISIBLE);
+            //tv.setVisibility(View.INVISIBLE);
+            RouterService svc = _routerService;
+            String status =
+                            "connected? " + Util.isConnected(this) +
+                            "\nhave ctx? " + (ctx != null) +
+                            "\nhave svc? " + (svc != null) +
+                            "\nis bound? " + _isBound +
+                            "\nsvc state: " + (svc == null ? "null" : svc.getState()) +
+                            "\ncan start? " + (svc == null ? "null" : svc.canManualStart()) +
+                            "\ncan stop? " + (svc == null ? "null" : svc.canManualStop());
+            tv.setText(status);
+            tv.setVisibility(View.VISIBLE);
         }
     }
 
diff --git a/src/net/i2p/android/router/service/RouterService.java b/src/net/i2p/android/router/service/RouterService.java
index ff722ea7e..91775dff9 100644
--- a/src/net/i2p/android/router/service/RouterService.java
+++ b/src/net/i2p/android/router/service/RouterService.java
@@ -27,7 +27,7 @@ import net.i2p.util.NativeBigInteger;
  *  Runs the router
  */
 public class RouterService extends Service {
-    private enum State {INIT, WAITING, STARTING, RUNNING,
+    public enum State {INIT, WAITING, STARTING, RUNNING,
                         // unplanned (router stopped itself), next: killSelf()
                         STOPPING, STOPPED,
                         // button, don't kill service when stopped, stay in MANUAL_STOPPED
@@ -218,6 +218,11 @@ public class RouterService extends Service {
         return rv;
     }
 
+    /** debug */
+    public String getState() {
+        return _state.toString();
+    }
+
     public boolean canManualStop() {
         return _state == State.WAITING || _state == State.STARTING || _state == State.RUNNING;
     }
diff --git a/src/net/i2p/android/router/util/Util.java b/src/net/i2p/android/router/util/Util.java
index 85637fd5a..bd909bdfa 100644
--- a/src/net/i2p/android/router/util/Util.java
+++ b/src/net/i2p/android/router/util/Util.java
@@ -7,6 +7,9 @@ import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.os.Build;
 
+import net.i2p.I2PAppContext;
+import net.i2p.util.Log;
+
 public abstract class Util {
     private static final boolean _isEmulator = Build.MODEL.equals("sdk");
 
@@ -39,4 +42,64 @@ public abstract class Util {
         return current;
     }
 
+    private static final String ANDROID_TAG = "I2P";
+
+    public static void e(String m) {
+        e(m, null);
+    }
+
+    /**
+     *  Log to the context logger if available (which goes to the console buffer
+     *  and to logcat), else just to logcat.
+     */
+    public static void e(String m, Throwable t) {
+        I2PAppContext ctx = I2PAppContext.getCurrentContext();
+        if (ctx != null)
+            ctx.logManager().getLog(Util.class).log(Log.ERROR, m, t);
+        else if (t != null)
+            android.util.Log.e(ANDROID_TAG, m + ' ' + t + ' ' + android.util.Log.getStackTraceString(t));
+        else
+            android.util.Log.e(ANDROID_TAG, m);
+    }
+
+    public static void w(String m) {
+        w(m, null);
+    }
+
+    public static void w(String m, Throwable t) {
+        I2PAppContext ctx = I2PAppContext.getCurrentContext();
+        if (ctx != null)
+            ctx.logManager().getLog(Util.class).log(Log.WARN, m, t);
+        else if (t != null)
+            android.util.Log.w(ANDROID_TAG, m + ' ' + t + ' ' + android.util.Log.getStackTraceString(t));
+        else
+            android.util.Log.w(ANDROID_TAG, m);
+    }
+
+    public static void i(String m) {
+        i(m, null);
+    }
+
+    public static void i(String m, Throwable t) {
+        I2PAppContext ctx = I2PAppContext.getCurrentContext();
+        if (ctx != null)
+            ctx.logManager().getLog(Util.class).log(Log.INFO, m, t);
+        else if (t != null)
+            android.util.Log.i(ANDROID_TAG, m + ' ' + t + ' ' + android.util.Log.getStackTraceString(t));
+        else
+            android.util.Log.i(ANDROID_TAG, m);
+    }
+    public static void d(String m) {
+        d(m, null);
+    }
+
+    public static void d(String m, Throwable t) {
+        I2PAppContext ctx = I2PAppContext.getCurrentContext();
+        if (ctx != null)
+            ctx.logManager().getLog(Util.class).log(Log.DEBUG, m, t);
+        else if (t != null)
+            android.util.Log.d(ANDROID_TAG, m + ' ' + t + ' ' + android.util.Log.getStackTraceString(t));
+        else
+            android.util.Log.d(ANDROID_TAG, m);
+    }
 }
diff --git a/src/net/i2p/util/LogWriter.java b/src/net/i2p/util/LogWriter.java
index be06b7c0c..22dcf9c7d 100644
--- a/src/net/i2p/util/LogWriter.java
+++ b/src/net/i2p/util/LogWriter.java
@@ -105,6 +105,12 @@ class LogWriter implements Runnable {
         else
             log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable());
 
+        // to be viewed on android screen
+        String val = LogRecordFormatter.formatRecord(_manager, rec, true);
+        _manager.getBuffer().add(val);
+        if (rec.getPriority() >= Log.ERROR)
+            _manager.getBuffer().addCritical(val);
+
         // we always add to the console buffer, but only sometimes write to stdout
         if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) {
             if (_manager.displayOnScreen()) {
@@ -114,6 +120,8 @@ class LogWriter implements Runnable {
         }
     }
 
+    private static final String ANDROID_LOG_TAG = "I2P";
+
     public void log(int priority, Class src, String name, String threadName, String msg) {
             if (src != null) {
                 String tag = src.getName();
@@ -121,15 +129,18 @@ class LogWriter implements Runnable {
                 if (dot >= 0)
                     tag = tag.substring(dot + 1);
                 android.util.Log.println(toAndroidLevel(priority),
-                                         tag,
-                                         '[' + threadName + "] " + msg);
+                                         ANDROID_LOG_TAG,
+                                         tag +
+                                         " [" + threadName + "] " + msg);
             } else if (name != null)
                 android.util.Log.println(toAndroidLevel(priority),
-                                         name,
-                                         '[' + threadName + "] " + msg);
+                                         ANDROID_LOG_TAG,
+                                         name +
+                                         " ["  + threadName + "] " + msg);
             else
                 android.util.Log.println(toAndroidLevel(priority),
-                                         threadName, msg);
+                                         ANDROID_LOG_TAG,
+                                         '[' + threadName + "] " + msg);
     }
 
     public void log(int priority, Class src, String name, String threadName, String msg, Throwable t) {
@@ -139,17 +150,20 @@ class LogWriter implements Runnable {
                 if (dot >= 0)
                     tag = tag.substring(dot + 1);
                 android.util.Log.println(toAndroidLevel(priority),
-                                         tag,
-                                         '[' + threadName + "] " + msg +
+                                         ANDROID_LOG_TAG,
+                                         tag +
+                                         " [" + threadName + "] " + msg +
                                          ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
             } else if (name != null)
                 android.util.Log.println(toAndroidLevel(priority),
-                                         name,
-                                         '[' + threadName + "] " + msg +
+                                         ANDROID_LOG_TAG,
+                                         name +
+                                         " [" + threadName + "] " + msg +
                                          ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
             else
                 android.util.Log.println(toAndroidLevel(priority),
-                                         threadName,
+                                         ANDROID_LOG_TAG,
+                                         '[' + threadName + "] " +
                                          msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
     }
 
-- 
GitLab