gui: Add display of forwarder status

Change-Id: I6748bea615ea2f56d9b222ce34e12e449cec7f9d
diff --git a/app/build.gradle b/app/build.gradle
index 86267a6..2a2b70c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -136,8 +136,8 @@
     compile 'net.named-data:jndn:0.4'
     compile 'net.named-data.jndn-xx:jndn-xx-util:0.0.1'
 
-    compile 'com.intel.jndn.utils:jndn-utils:0.9.5'
-    compile 'com.intel.jndn.management:jndn-management:0.9.5'
+    compile 'com.intel.jndn.utils:jndn-utils:0.9.7'
+    compile 'com.intel.jndn.management:jndn-management:0.9.7'
     compile 'com.google.protobuf:protobuf-java:2.6.1'
 
     compile 'joda-time:joda-time:2.7'
diff --git a/app/src/main/java/net/named_data/nfd/MainFragment.java b/app/src/main/java/net/named_data/nfd/MainFragment.java
index 7eb03aa..68e9690 100644
--- a/app/src/main/java/net/named_data/nfd/MainFragment.java
+++ b/app/src/main/java/net/named_data/nfd/MainFragment.java
@@ -25,6 +25,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -39,9 +40,16 @@
 import android.view.ViewGroup;
 import android.widget.CompoundButton;
 import android.widget.Switch;
+import android.widget.TextView;
+
+import com.intel.jndn.management.types.ForwarderStatus;
 
 import net.named_data.nfd.service.NfdService;
 import net.named_data.nfd.utils.G;
+import net.named_data.nfd.utils.Nfdc;
+
+import org.joda.time.Period;
+import org.joda.time.format.PeriodFormat;
 
 public class MainFragment extends Fragment {
 
@@ -84,6 +92,20 @@
       }
     });
 
+    m_nfdStatusView = (ViewGroup)v.findViewById(R.id.status_view);
+    m_nfdStatusView.setVisibility(View.GONE);
+    m_versionView = (TextView)v.findViewById(R.id.version);
+    m_uptimeView = (TextView)v.findViewById(R.id.uptime);
+    m_nameTreeEntriesView = (TextView)v.findViewById(R.id.name_tree_entries);
+    m_fibEntriesView = (TextView)v.findViewById(R.id.fib_entries);
+    m_pitEntriesView = (TextView)v.findViewById(R.id.pit_entries);
+    m_measurementEntriesView = (TextView)v.findViewById(R.id.measurement_entries);
+    m_csEntriesView = (TextView)v.findViewById(R.id.cs_entries);
+    m_inInterestsView = (TextView)v.findViewById(R.id.in_interests);
+    m_outInterestsView = (TextView)v.findViewById(R.id.out_interests);
+    m_inDataView = (TextView)v.findViewById(R.id.in_data);
+    m_outDataView = (TextView)v.findViewById(R.id.out_data);
+
     return v;
   }
 
@@ -101,6 +123,7 @@
     super.onPause();
 
     unbindNfdService();
+    m_handler.removeCallbacks(m_statusUpdateRunnable);
     m_handler.removeCallbacks(m_retryConnectionToNfdService);
   }
 
@@ -145,6 +168,10 @@
 
     m_nfdStartStopSwitch.setText(R.string.stopping_nfd);
     sendNfdServiceMessage(NfdService.STOP_NFD_SERVICE);
+
+    // disable status block
+    m_nfdStatusView.setVisibility(View.GONE);
+    m_handler.removeCallbacks(m_statusUpdateRunnable);
   }
 
   /**
@@ -204,6 +231,8 @@
         case NfdService.NFD_SERVICE_RUNNING:
           setNfdServiceRunning();
           G.Log("ClientHandler: NFD is Running.");
+
+          m_handler.post(m_statusUpdateRunnable);
           break;
 
         case NfdService.NFD_SERVICE_STOPPED:
@@ -275,6 +304,59 @@
     }
   };
 
+  private class StatusUpdateTask extends AsyncTask<Void, Void, ForwarderStatus> {
+    /**
+     * @param voids
+     * @return ForwarderStatus if operation succeeded, null if operation failed
+     */
+    @Override
+    protected ForwarderStatus
+    doInBackground(Void... voids)
+    {
+      try {
+        Nfdc nfdc = new Nfdc();
+        ForwarderStatus fs = nfdc.generalStatus();
+        nfdc.shutdown();
+        return fs;
+      }
+      catch (Exception e) {
+        G.Log("Error communicating with NFD (" + e.getMessage() + ")");
+        return null;
+      }
+    }
+
+    @Override
+    protected void
+    onPostExecute(ForwarderStatus fs)
+    {
+      if (fs == null) {
+        // Maybe display error message from result.second
+      }
+      else {
+        m_versionView.setText(fs.getNfdVersion());
+        m_uptimeView.setText(PeriodFormat.getDefault().print(new Period(
+          fs.getCurrentTimestamp() - fs.getStartTimestamp())));
+        m_nameTreeEntriesView.setText(String.valueOf(
+          fs.getNumNameTreeEntries()));
+        m_fibEntriesView.setText(String.valueOf(fs.getNumFibEntries()));
+        m_pitEntriesView.setText(String.valueOf(fs.getNumPitEntries()));
+        m_measurementEntriesView.setText(String.valueOf(
+          fs.getNumMeasurementEntries()));
+        m_csEntriesView.setText(String.valueOf(fs.getNumCsEntries()));
+
+        m_inInterestsView.setText(String.valueOf(fs.getNumInInterests()));
+        m_outInterestsView.setText(String.valueOf(
+          fs.getNumOutInterests()));
+        m_inDataView.setText(String.valueOf(fs.getNumInDatas()));
+        m_outDataView.setText(String.valueOf(fs.getNumOutDatas()));
+
+        m_nfdStatusView.setVisibility(View.VISIBLE);
+      }
+
+      m_handler.postDelayed(m_statusUpdateRunnable, 5000);
+    }
+  }
+
   //////////////////////////////////////////////////////////////////////////////
 
   /** Button that starts and stops the NFD */
@@ -289,7 +371,29 @@
   /** Messenger connection to NfdService */
   private Messenger m_nfdServiceMessenger = null;
 
+  /** ListView holding NFD status information */
+  private ViewGroup m_nfdStatusView;
+
+  private TextView m_versionView;
+  private TextView m_uptimeView;
+  private TextView m_nameTreeEntriesView;
+  private TextView m_fibEntriesView;
+  private TextView m_pitEntriesView;
+  private TextView m_measurementEntriesView;
+  private TextView m_csEntriesView;
+  private TextView m_inInterestsView;
+  private TextView m_outInterestsView;
+  private TextView m_inDataView;
+  private TextView m_outDataView;
+
   private Handler m_handler;
+  private Runnable m_statusUpdateRunnable = new Runnable() {
+    @Override
+    public void run()
+    {
+      new StatusUpdateTask().execute();
+    }
+  };
 
   private static final String PREF_NFD_SERVICE_STATUS = "NFD_SERVICE_STATUS";
 }
diff --git a/app/src/main/java/net/named_data/nfd/RouteListFragment.java b/app/src/main/java/net/named_data/nfd/RouteListFragment.java
index f6c787f..61d39d5 100644
--- a/app/src/main/java/net/named_data/nfd/RouteListFragment.java
+++ b/app/src/main/java/net/named_data/nfd/RouteListFragment.java
@@ -305,25 +305,25 @@
     protected String
     doInBackground(Void... params)
     {
+      Nfdc nfdc = new Nfdc();
       try {
-        Nfdc nfdc = new Nfdc();
         int faceId = nfdc.faceCreate(m_faceUri);
-        boolean ok = nfdc.ribRegisterPrefix(new Name(m_prefix), faceId, 10, true, false);
+        nfdc.ribRegisterPrefix(new Name(m_prefix), faceId, 10, true, false);
         nfdc.shutdown();
-        if (ok) {
-          return "OK";
-        }
-        else {
-          return "Failed register prefix";
-        }
-      } catch (FaceUri.CanonizeError e) {
+        return "OK";
+      }
+      catch (FaceUri.CanonizeError e) {
         return "Error creating face (" + e.getMessage() + ")";
-      } catch (FaceUri.Error e) {
+      }
+      catch (FaceUri.Error e) {
         return "Error creating face (" + e.getMessage() + ")";
       }
       catch (Exception e) {
         return "Error communicating with NFD (" + e.getMessage() + ")";
       }
+      finally {
+        nfdc.shutdown();
+      }
     }
 
     @Override
diff --git a/app/src/main/java/net/named_data/nfd/utils/Nfdc.java b/app/src/main/java/net/named_data/nfd/utils/Nfdc.java
index 5517449..b376501 100644
--- a/app/src/main/java/net/named_data/nfd/utils/Nfdc.java
+++ b/app/src/main/java/net/named_data/nfd/utils/Nfdc.java
@@ -21,6 +21,7 @@
 
 import com.intel.jndn.management.NFD;
 import com.intel.jndn.management.types.FaceStatus;
+import com.intel.jndn.management.types.ForwarderStatus;
 import com.intel.jndn.management.types.RibEntry;
 
 import net.named_data.jndn.ControlParameters;
@@ -72,6 +73,16 @@
   }
 
   /**
+   * Get general NFD status
+   */
+  public ForwarderStatus
+  generalStatus() throws Exception
+  {
+    return NFD.getForwarderStatus(m_face);
+  }
+
+
+  /**
    * Adds a nexthop to a FIB entry
    * <p>
    * If the FIB entry does not exist, it is inserted automatically
@@ -94,18 +105,18 @@
   /**
    * Registers name to the given faceId or faceUri
    */
-  public boolean
+  public void
   ribRegisterPrefix(Name prefix, int faceId, int cost, boolean isChildInherit, boolean isCapture) throws Exception
   {
     ForwardingFlags flags = new ForwardingFlags();
     flags.setChildInherit(isChildInherit);
     flags.setCapture(isCapture);
-    return NFD.register(m_face,
-                        new ControlParameters()
-                          .setName(prefix)
-                          .setFaceId(faceId)
-                          .setCost(cost)
-                          .setForwardingFlags(flags));
+    NFD.register(m_face,
+                 new ControlParameters()
+                   .setName(prefix)
+                   .setFaceId(faceId)
+                   .setCost(cost)
+                   .setForwardingFlags(flags));
   }
 
   /**
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index 9fa4afa..7a8c93a 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -1,17 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
+<ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    style="@style/default_linear_layout_padding"
-    >
+    android:layout_height="wrap_content">
+
+  <LinearLayout
+      style="@style/default_linear_layout_padding"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:orientation="vertical"
+      >
 
     <TextView
+        style="?android:listSeparatorTextViewStyle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/pref_category_title_general"
-        style="?android:listSeparatorTextViewStyle"
         />
 
     <Switch
@@ -22,4 +26,106 @@
         android:text="@string/checking_on_nfd"
         />
 
-</LinearLayout>
\ No newline at end of file
+    <LinearLayout android:id="@+id/status_view"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"
+                  android:visibility="gone">
+
+      <TextView style="?android:listSeparatorTextViewStyle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/pref_category_title_status"
+                />
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/version" />
+
+        <TextView android:id="@+id/version"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/uptime" />
+
+        <TextView android:id="@+id/uptime"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/name_tree_entries" />
+
+        <TextView android:id="@+id/name_tree_entries"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/fib_entries" />
+
+        <TextView android:id="@+id/fib_entries"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/pit_entries" />
+
+        <TextView android:id="@+id/pit_entries"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/measurement_entries" />
+
+        <TextView android:id="@+id/measurement_entries"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/cs_entries" />
+
+        <TextView android:id="@+id/cs_entries"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/in_interests" />
+
+        <TextView android:id="@+id/in_interests"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/out_interests" />
+
+        <TextView android:id="@+id/out_interests"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/in_data" />
+
+        <TextView android:id="@+id/in_data"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+      <LinearLayout style="@style/main_fragment_linear_layout">
+        <TextView style="@style/main_fragment_list_title"
+                  android:text="@string/out_data" />
+
+        <TextView android:id="@+id/out_data"
+                  style="@style/main_fragment_list_value" />
+      </LinearLayout>
+
+    </LinearLayout>
+  </LinearLayout>
+</ScrollView>
diff --git a/app/src/main/res/layout/status_item.xml b/app/src/main/res/layout/status_item.xml
new file mode 100644
index 0000000..549de06
--- /dev/null
+++ b/app/src/main/res/layout/status_item.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/main_fragment_linear_layout">
+    <TextView style="@style/main_fragment_list_title"
+              android:id="@+id/title" />
+
+    <TextView style="@style/main_fragment_list_value"
+              android:id="@+id/value" />
+</LinearLayout>
diff --git a/app/src/main/res/values/strings_main_activity.xml b/app/src/main/res/values/strings_main_activity.xml
index 9a41a2f..8b67095 100644
--- a/app/src/main/res/values/strings_main_activity.xml
+++ b/app/src/main/res/values/strings_main_activity.xml
@@ -1,7 +1,19 @@
 <resources>
     <!-- General -->
     <string name="pref_category_title_general">General</string>
-    <string name="pref_category_title_general_key">General_Key</string>
+    <string name="pref_category_title_status">NFD Status</string>
+
+    <string name="version">Version</string>
+    <string name="uptime">Uptime</string>
+    <string name="name_tree_entries">NameTree entries</string>
+    <string name="fib_entries">FIB entries</string>
+    <string name="pit_entries">PIT Entries</string>
+    <string name="measurement_entries">Measurement entries</string>
+    <string name="cs_entries">CS entries</string>
+    <string name="in_interests">In interests</string>
+    <string name="out_interests">Out interests</string>
+    <string name="in_data">In data</string>
+    <string name="out_data">Out data</string>
 
     <string-array name="pref_sync_face_titles">
         <item>localhost</item>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 08a8a5c..f851cec 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -58,4 +58,25 @@
         <item name="android:layout_gravity">right</item>
     </style>
 
+    <style name="main_fragment_linear_layout">
+        <item name="android:orientation">horizontal</item>
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="main_fragment_list_title">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textColor">@android:color/primary_text_light</item>
+    </style>
+
+    <style name="main_fragment_list_value">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:gravity">right</item>
+        <item name="android:textColor">@android:color/secondary_text_dark</item>
+        <item name="android:layout_gravity">right</item>
+    </style>
 </resources>