gui: Fix bug with ping unexpectedly starting after reopening app

Refs: #4688
Change-Id: Ib12c300d5a351e9dc76499eacfb3f96d5a42b97c
diff --git a/app/src/main/java/net/named_data/nfd/DrawerFragment.java b/app/src/main/java/net/named_data/nfd/DrawerFragment.java
index 0e981c9..987ebd4 100644
--- a/app/src/main/java/net/named_data/nfd/DrawerFragment.java
+++ b/app/src/main/java/net/named_data/nfd/DrawerFragment.java
@@ -142,9 +142,12 @@
             bottomItem.setChecked(true);
           }
           else {
-            MenuItem selectedBottomItem = m_bottomNav.getMenu().getItem(m_bottomNav.getSelectedItemId());
-            if (selectedBottomItem != null) {
-              selectedBottomItem.setChecked(false);
+            if (m_bottomNav.isSelected()) {
+              MenuItem selectedBottomItem = m_bottomNav.getMenu().getItem(
+                m_bottomNav.getSelectedItemId());
+              if (selectedBottomItem != null) {
+                selectedBottomItem.setChecked(false);
+              }
             }
           }
 
diff --git a/app/src/main/java/net/named_data/nfd/FaceListFragment.java b/app/src/main/java/net/named_data/nfd/FaceListFragment.java
index aff4110..1097db0 100644
--- a/app/src/main/java/net/named_data/nfd/FaceListFragment.java
+++ b/app/src/main/java/net/named_data/nfd/FaceListFragment.java
@@ -206,6 +206,16 @@
   }
 
   @Override
+  public void onHiddenChanged(boolean hidden)
+  {
+    G.Log("onHiddenChanged: " + Boolean.toString(hidden));
+    super.onHiddenChanged(hidden);
+    if (!hidden) {
+      startFaceListRetrievalTask();
+    }
+  }
+
+  @Override
   public void onPause() {
     super.onPause();
     stopFaceListRetrievalTask();
@@ -287,8 +297,6 @@
     // Update UI
     m_faceListInfoUnavailableView.setVisibility(View.GONE);
 
-    // Stop if running; before starting the new Task
-    stopFaceListRetrievalTask();
     startFaceListRetrievalTask();
   }
 
@@ -296,6 +304,8 @@
    * Create a new AsyncTask for face list information retrieval.
    */
   private void startFaceListRetrievalTask() {
+    // Stop if running; before starting the new Task
+    stopFaceListRetrievalTask();
     m_faceListAsyncTask = new FaceListAsyncTask();
     m_faceListAsyncTask.execute();
   }
diff --git a/app/src/main/java/net/named_data/nfd/MainActivity.java b/app/src/main/java/net/named_data/nfd/MainActivity.java
index 937ce89..a6824c2 100644
--- a/app/src/main/java/net/named_data/nfd/MainActivity.java
+++ b/app/src/main/java/net/named_data/nfd/MainActivity.java
@@ -21,6 +21,7 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 
@@ -90,31 +91,79 @@
   protected void onNewIntent(Intent intent) {
     super.onNewIntent(intent);
     setIntent(intent);
-    FragmentManager fragmentManager = getSupportFragmentManager();
 
     int drawItem = getIntent().getIntExtra(INTENT_KEY_FRAGMENT_TAG, R.id.nav_general);
     if (drawItem == R.id.nav_general) {
-      MainFragment mainFragment =  MainFragment.newInstance();
-      fragmentManager
-          .beginTransaction()
-          .replace(R.id.main_fragment_container, mainFragment)
-          .commit();
+      onDrawerItemSelected(R.id.nav_general,
+          getApplicationContext().getResources().getString(R.string.drawer_item_general));
     }
   }
 
-  /**
-   * Convenience method that replaces the main fragment container with the
-   * new fragment and adding the current transaction to the backstack.
-   *
-   * @param fragment Fragment to be displayed in the main fragment container.
-   */
-  private void replaceContentFragmentWithBackstack(Fragment fragment) {
+  @FunctionalInterface
+  public interface FragmentCreator {
+    Fragment makeFragment();
+  }
+
+  private void
+  showFragment(String fragmentTag, boolean addBackStack, FragmentCreator fragmentCreator) {
     FragmentManager fragmentManager = getSupportFragmentManager();
-    fragmentManager.beginTransaction()
-        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
-        .replace(R.id.main_fragment_container, fragment)
-        .addToBackStack(null)
+    Fragment fragment = fragmentManager.findFragmentByTag(fragmentTag);
+
+    if (fragment == null) {
+      fragment = fragmentCreator.makeFragment();
+      if (fragment == null) {
+        G.Log("Requested to show " + fragmentTag + ", but fragment cannot be instantiated");
+        return;
+      }
+
+      FragmentTransaction transaction = fragmentManager.beginTransaction();
+      transaction.add(R.id.main_fragment_container, fragment, fragmentTag);
+      if (addBackStack) {
+        G.Log("Adding with backstack: " + lastFragmentTag);
+        transaction.addToBackStack(lastFragmentTag);
+      }
+      transaction.commit();
+    }
+    else {
+      FragmentTransaction transaction = fragmentManager.beginTransaction();
+      transaction.show(fragment);
+      if (addBackStack) {
+        G.Log("Showing with backstack: " + lastFragmentTag);
+        transaction.addToBackStack(lastFragmentTag);
+      }
+      transaction.commit();
+    }
+
+    if (lastFragment != null && lastFragment != fragment) {
+      fragmentManager.beginTransaction()
+        .hide(lastFragment)
         .commit();
+    }
+
+    lastFragment = fragment;
+    lastFragmentTag = fragmentTag;
+  }
+
+  @Override
+  public void onBackPressed()
+  {
+    FragmentManager fragmentManager = getSupportFragmentManager();
+
+    if (fragmentManager.getBackStackEntryCount() > 0) {
+      String name = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();
+      Fragment fragment = fragmentManager.findFragmentByTag(name);
+
+      G.Log("Returning to " + name + " , " + fragment);
+      if (fragment != null) {
+        fragmentManager.beginTransaction()
+          .show(fragment)
+          .commit();
+
+        lastFragment = fragment;
+        lastFragmentTag = name;
+      }
+    }
+    super.onBackPressed();
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -124,53 +173,41 @@
   onDrawerItemSelected(int itemCode, CharSequence itemTitle) {
     G.Log("onDrawerItemSelected: " + itemTitle);
     String fragmentTag = "net.named-data.nfd.content-" + String.valueOf(itemCode);
-    FragmentManager fragmentManager = getSupportFragmentManager();
 
-    // Create fragment according to user's selection
-    Fragment fragment = fragmentManager.findFragmentByTag(fragmentTag);
-    if (fragment == null) {
+    showFragment(fragmentTag, false, () -> {
       switch (itemCode) {
         case R.id.nav_general:
-          fragment = MainFragment.newInstance();
-          break;
+          return MainFragment.newInstance();
         case R.id.nav_faces:
-          fragment = FaceListFragment.newInstance();
-          break;
+          return FaceListFragment.newInstance();
         case R.id.nav_routes:
-          fragment = RouteListFragment.newInstance();
-          break;
+          return RouteListFragment.newInstance();
         case R.id.nav_ping:
-          fragment = PingClientFragment.newInstance();
-          break;
-        // TODO: Placeholders; Fill these in when their fragments have been created
+          return PingClientFragment.newInstance();
         //    case DRAWER_ITEM_STRATEGIES:
-        //      break;
+        //      return TODO: Placeholders; Fill these in when their fragments have been created
         case R.id.nav_wifidirect:
-          fragment = WiFiDirectFragment.newInstance();
-          break;
+          return WiFiDirectFragment.newInstance();
         default:
           // Invalid; Nothing else needs to be done
-          return;
+          return null;
       }
-    }
+    });
 
     ActionBar actionBar = getSupportActionBar();
     actionBar.setTitle(itemTitle);
-
-    fragmentManager.beginTransaction()
-      .replace(R.id.main_fragment_container, fragment, fragmentTag)
-      .commit();
   }
 
   @Override
   public void onFaceItemSelected(FaceStatus faceStatus) {
-    replaceContentFragmentWithBackstack(FaceStatusFragment.newInstance(faceStatus));
+    showFragment(FaceStatusFragment.class.toString(), true,
+                 () -> FaceStatusFragment.newInstance(faceStatus));
   }
 
   @Override
-  public void onRouteItemSelected(RibEntry ribEntry)
-  {
-    replaceContentFragmentWithBackstack(RouteInfoFragment.newInstance(ribEntry));
+  public void onRouteItemSelected(RibEntry ribEntry) {
+    showFragment(RouteInfoFragment.class.toString(), true,
+                 () -> RouteInfoFragment.newInstance(ribEntry));
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -178,6 +215,11 @@
   /** Reference to drawer fragment */
   private DrawerFragment m_drawerFragment;
 
+  /** Record the last fragment */
+  private Fragment lastFragment = null;
+
+  private String lastFragmentTag = "";
+
   /** Indent key for jump to a fragment */
   public static final String INTENT_KEY_FRAGMENT_TAG = "fragmentTag";
 }
diff --git a/app/src/main/java/net/named_data/nfd/PingClientFragment.java b/app/src/main/java/net/named_data/nfd/PingClientFragment.java
index 37ab12f..66ffdfb 100644
--- a/app/src/main/java/net/named_data/nfd/PingClientFragment.java
+++ b/app/src/main/java/net/named_data/nfd/PingClientFragment.java
@@ -150,8 +150,8 @@
   }
 
   @Override
-  public void onStop() {
-    super.onStop();
+  public void onDestroy() {
+    super.onDestroy();
     if (m_client != null) {
       m_client.setListener(null);
       m_client.stop();
@@ -171,15 +171,6 @@
   }
 
   @Override
-  public void onStart() {
-    super.onStart();
-    if (m_client != null) {
-      m_client.setListener(this);
-      m_client.start();
-    }
-  }
-
-  @Override
   public void onPingResponse(final String prefix, final long seq, final double elapsedTime) {
     this.getActivity().runOnUiThread(new Runnable() {
         @Override
diff --git a/app/src/main/java/net/named_data/nfd/RouteInfoFragment.java b/app/src/main/java/net/named_data/nfd/RouteInfoFragment.java
index e3a3700..f20ee18 100644
--- a/app/src/main/java/net/named_data/nfd/RouteInfoFragment.java
+++ b/app/src/main/java/net/named_data/nfd/RouteInfoFragment.java
@@ -242,14 +242,24 @@
     m_routeListAsyncTask = new RouteListAsyncTask();
     m_routeListAsyncTask.execute();
 
-    stopRouteFaceListRetrievalTask();
     startRouteFaceListRetrievalTask();
   }
 
+
+  @Override
+  public void onHiddenChanged(boolean hidden)
+  {
+    super.onHiddenChanged(hidden);
+    if (!hidden) {
+      startRouteFaceListRetrievalTask();
+    }
+  }
+
   /**
    * Create a new AsyncTask for face list information retrieval.
    */
   private void startRouteFaceListRetrievalTask() {
+    stopRouteFaceListRetrievalTask();
     m_faceListAsyncTask = new FaceListAsyncTask();
     m_faceListAsyncTask.execute();
   }
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 3d46aca..977a43e 100644
--- a/app/src/main/java/net/named_data/nfd/RouteListFragment.java
+++ b/app/src/main/java/net/named_data/nfd/RouteListFragment.java
@@ -172,6 +172,15 @@
   }
 
   @Override
+  public void onHiddenChanged(boolean hidden)
+  {
+    super.onHiddenChanged(hidden);
+    if (!hidden) {
+      startRouteListInfoRetrievalTask();
+    }
+  }
+
+  @Override
   public void
   onPause() {
     super.onPause();
@@ -299,8 +308,6 @@
     // Update UI
     m_routeListInfoUnavailableView.setVisibility(View.GONE);
 
-    // Stop if running; before starting the new Task
-    stopRouteListInfoRetrievalTask();
     startRouteListInfoRetrievalTask();
   }
 
@@ -309,6 +316,8 @@
    */
   private void
   startRouteListInfoRetrievalTask() {
+    // Stop if running; before starting the new Task
+    stopRouteListInfoRetrievalTask();
     m_routeListAsyncTask = new RouteListAsyncTask();
     m_routeListAsyncTask.execute();
   }